Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make aria-labels localizable #2282

Merged
merged 16 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion i18next-parser.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module.exports = {
createOldCatalogs: false,
input: ['./src/**/*.{tsx,ts}'],
keepRemoved: true,
keySeparator: false,
keySeparator: '/',
locales: ['de', 'en', 'es', 'fr', 'hi', 'it', 'ja', 'ko', 'nl', 'pt', 'ru', 'tr'],
namespaceSeparator: false,
output: 'src/i18n/$LOCALE.json',
Expand Down
6 changes: 5 additions & 1 deletion src/components/ChannelHeader/ChannelHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ const UnMemoizedChannelHeader = <

return (
<div className='str-chat__header-livestream str-chat__channel-header'>
<button aria-label='Menu' className='str-chat__header-hamburger' onClick={openMobileNav}>
<button
aria-label={t('aria/Menu')}
className='str-chat__header-hamburger'
onClick={openMobileNav}
>
<MenuIcon />
</button>
<Avatar
Expand Down
4 changes: 3 additions & 1 deletion src/components/ChannelList/ChannelListMessenger.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { LoadingChannels } from '../Loading/LoadingChannels';
import type { APIErrorResponse, Channel, ErrorFromResponse } from 'stream-chat';

import type { DefaultStreamChatGenerics } from '../../types/types';
import { useTranslationContext } from '../../context';

export type ChannelListMessengerProps<
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
Expand Down Expand Up @@ -39,6 +40,7 @@ export const ChannelListMessenger = <
LoadingErrorIndicator = ChatDown,
LoadingIndicator = LoadingChannels,
} = props;
const { t } = useTranslationContext('ChannelListMessenger');

if (error) {
return <LoadingErrorIndicator type='Connection Error' />;
Expand All @@ -51,7 +53,7 @@ export const ChannelListMessenger = <
return (
<div className='str-chat__channel-list-messenger str-chat__channel-list-messenger-react'>
<div
aria-label='Channel list'
aria-label={t('aria/Channel list')}
className='str-chat__channel-list-messenger__main str-chat__channel-list-messenger-react__main'
role='listbox'
>
Expand Down
23 changes: 15 additions & 8 deletions src/components/ChannelList/__tests__/ChannelList.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,14 @@ import {
ChannelPreviewMessenger,
} from '../../ChannelPreview';

import { ChatContext, useChannelListContext, useChatContext } from '../../../context';
import {
ChatContext,
TranslationContext,
useChannelListContext,
useChatContext,
} from '../../../context';
import { ChannelListMessenger } from '../ChannelListMessenger';
import { initClientWithChannels } from '../../../mock-builders';
import { initClientWithChannels, mockTranslationContext } from '../../../mock-builders';

expect.extend(toHaveNoViolations);

Expand Down Expand Up @@ -603,12 +608,14 @@ describe('ChannelList', () => {
...chatContext,
}}
>
<ChannelList
filters={{}}
options={{ presence: true, state: true }}
showChannelSearch
{...channeListProps}
/>
<TranslationContext.Provider value={mockTranslationContext}>
<ChannelList
filters={{}}
options={{ presence: true, state: true }}
showChannelSearch
{...channeListProps}
/>
</TranslationContext.Provider>
</ChatContext.Provider>,
);

Expand Down
26 changes: 15 additions & 11 deletions src/components/ChannelSearch/SearchResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,17 +142,21 @@ const DefaultSearchResultItem = <
const ResultsContainer = ({
children,
popupResults,
}: PropsWithChildren<{ popupResults?: boolean }>) => (
<div
aria-label='Channel search results'
className={clsx(
`str-chat__channel-search-container str-chat__channel-search-result-list`,
popupResults ? 'popup' : 'inline',
)}
>
{children}
</div>
);
}: PropsWithChildren<{ popupResults?: boolean }>) => {
const { t } = useTranslationContext('ResultsContainer');

return (
<div
aria-label={t('aria/Channel search results')}
className={clsx(
`str-chat__channel-search-container str-chat__channel-search-result-list`,
popupResults ? 'popup' : 'inline',
)}
>
{children}
</div>
);
};

export type SearchResultsController<
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
Expand Down
2 changes: 1 addition & 1 deletion src/components/Emojis/EmojiPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export const EmojiPicker = (props: EmojiPickerProps) => {
)}
<button
aria-expanded={displayPicker}
aria-label='Emoji picker'
aria-label={t('aria/Emoji picker')}
className={props.buttonClassName ?? buttonClassName}
onClick={() => setDisplayPicker((cv) => !cv)}
ref={setReferenceElement}
Expand Down
2 changes: 1 addition & 1 deletion src/components/LoadMore/LoadMoreButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const UnMemoizedLoadMoreButton = ({
return (
<div className='str-chat__load-more-button'>
<button
aria-label='Load More Channels'
aria-label={t('aria/Load More Channels')}
className='str-chat__load-more-button__button str-chat__cta-button'
data-testid='load-more-button'
disabled={loading}
Expand Down
7 changes: 5 additions & 2 deletions src/components/Message/MessageOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { MessageActions } from '../MessageActions';
import { MessageContextValue, useMessageContext } from '../../context/MessageContext';

import type { DefaultStreamChatGenerics, IconProps } from '../../types/types';
import { useTranslationContext } from '../../context';

export type MessageOptionsProps<
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
Expand Down Expand Up @@ -56,6 +57,8 @@ const UnMemoizedMessageOptions = <
threadList,
} = useMessageContext<StreamChatGenerics>('MessageOptions');

const { t } = useTranslationContext('MessageOptions');

const handleOpenThread = propHandleOpenThread || contextHandleOpenThread;

const messageActions = getMessageActions();
Expand Down Expand Up @@ -87,7 +90,7 @@ const UnMemoizedMessageOptions = <
)}
{shouldShowReplies && (
<button
aria-label='Open Thread'
aria-label={t('aria/Open Thread')}
className={`str-chat__message-${theme}__actions__action str-chat__message-${theme}__actions__action--thread str-chat__message-reply-in-thread-button`}
data-testid='thread-action'
onClick={handleOpenThread}
Expand All @@ -98,7 +101,7 @@ const UnMemoizedMessageOptions = <
{shouldShowReactions && (
<button
aria-expanded={showDetailedReactions}
aria-label='Open Reaction Selector'
aria-label={t('aria/Open Reaction Selector')}
className={`str-chat__message-${theme}__actions__action str-chat__message-${theme}__actions__action--reactions str-chat__message-reactions-button`}
data-testid='message-reaction-action'
onClick={onReactionListClick}
Expand Down
5 changes: 4 additions & 1 deletion src/components/MessageActions/MessageActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { MessageContextValue, useMessageContext } from '../../context/MessageCon

import type { DefaultStreamChatGenerics, IconProps } from '../../types/types';
import { useMessageActionsBoxPopper } from './hooks';
import { useTranslationContext } from '../../context';

type MessageContextPropsToPick =
| 'getMessageActions'
Expand Down Expand Up @@ -76,6 +77,8 @@ export const MessageActions = <
setEditingState,
} = useMessageContext<StreamChatGenerics>('MessageActions');

const { t } = useTranslationContext('MessageActions');

const getMessageActions = propGetMessageActions || contextGetMessageActions;
const handleDelete = propHandleDelete || contextHandleDelete;
const handleFlag = propHandleFlag || contextHandleFlag;
Expand Down Expand Up @@ -156,7 +159,7 @@ export const MessageActions = <
<button
aria-expanded={actionsBoxOpen}
aria-haspopup='true'
aria-label='Open Message Actions Menu'
aria-label={t('aria/Open Message Actions Menu')}
className='str-chat__message-actions-box-button'
ref={actionsBoxButtonRef}
>
Expand Down
6 changes: 5 additions & 1 deletion src/components/MessageActions/MessageActionsBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ const UnMemoizedMessageActionsBox = React.forwardRef(

return (
<div {...restDivProps} className={rootClassName} data-testid='message-actions-box' ref={ref}>
<div aria-label='Message Options' className='str-chat__message-actions-list' role='listbox'>
<div
aria-label={t('aria/Message Options')}
className='str-chat__message-actions-list'
role='listbox'
>
<CustomMessageActionsList customMessageActions={customMessageActions} message={message} />
{messageActions.indexOf(MESSAGE_ACTIONS.quote) > -1 && (
<button
Expand Down
2 changes: 1 addition & 1 deletion src/components/MessageInput/MessageInputFlat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ const MessageInputV2 = <
<div className='str-chat__file-input-container' data-testid='file-upload-button'>
<UploadButton
accept={acceptedFiles?.join(',')}
aria-label='File upload'
aria-label={t('aria/File upload')}
className='str-chat__file-input'
data-testid='file-input'
disabled={!isUploadEnabled || maxFilesLeft === 0}
Expand Down
2 changes: 1 addition & 1 deletion src/components/MessageInput/QuotedMessagePreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const QuotedMessagePreviewHeader = <
{t<string>('Reply to Message')}
</div>
<button
aria-label='Cancel Reply'
aria-label={t('aria/Cancel Reply')}
className='str-chat__square-button str-chat__quoted-message-remove'
onClick={() => setQuotedMessage(undefined)}
>
Expand Down
3 changes: 2 additions & 1 deletion src/components/MessageInput/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,11 @@ export const SendButton = <
...rest
}: SendButtonProps<StreamChatGenerics>) => {
const { themeVersion } = useChatContext('SendButton');
const { t } = useTranslationContext('SendButton');

return (
<button
aria-label='Send'
aria-label={t('aria/Send')}
className='str-chat__send-button'
data-testid='send-button'
onClick={sendMessage}
Expand Down
4 changes: 3 additions & 1 deletion src/components/ReactFileUtilities/FileUploadButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { PropsWithChildren } from 'react';

import { AttachmentIcon } from './icons';
import { UploadButton } from './UploadButton';
import { useTranslationContext } from '../../context';

export type FileUploadButtonProps = {
handleFiles: (files: FileList | File[]) => void;
Expand All @@ -22,6 +23,7 @@ export const FileUploadButton = ({
accepts,
resetOnChange = true,
}: PropsWithChildren<FileUploadButtonProps>) => {
const { t } = useTranslationContext('FileUploadButton');
let className = 'rfu-file-upload-button';
if (disabled) {
className = `${className} rfu-file-upload-button--disabled`;
Expand All @@ -32,7 +34,7 @@ export const FileUploadButton = ({
<label>
<UploadButton
accept={Array.isArray(accepts) ? accepts.join(',') : accepts}
aria-label='File input'
aria-label={t('aria/File input')}
className='rfu-file-input'
disabled={disabled}
multiple={multiple}
Expand Down
26 changes: 15 additions & 11 deletions src/components/ReactFileUtilities/IconButton.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { MouseEventHandler, PropsWithChildren } from 'react';
import { useTranslationContext } from '../../context';

export type IconButtonProps = {
onClick?: MouseEventHandler<HTMLButtonElement>;
Expand All @@ -7,14 +8,17 @@ export type IconButtonProps = {
/**
* This is simply a button wrapper, adds a div with `role="button"` and a onClick
*/
export const IconButton = ({ children, onClick }: PropsWithChildren<IconButtonProps>) => (
<button
aria-label='Cancel upload'
className='rfu-icon-button'
data-testid='cancel-upload-button'
onClick={onClick}
type='button'
>
{children}
</button>
);
export const IconButton = ({ children, onClick }: PropsWithChildren<IconButtonProps>) => {
const { t } = useTranslationContext('IconButton');
return (
<button
aria-label={t('aria/Cancel upload')}
className='rfu-icon-button'
data-testid='cancel-upload-button'
onClick={onClick}
type='button'
>
{children}
</button>
);
};
5 changes: 4 additions & 1 deletion src/components/ReactFileUtilities/ImagePreviewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { RetryIcon } from './icons';

import type { ImageUpload } from './types';
import clsx from 'clsx';
import { useTranslationContext } from '../../context';

type CustomMouseEvent = (id: string, event: MouseEvent<HTMLButtonElement>) => void;

Expand Down Expand Up @@ -34,6 +35,8 @@ export const ImagePreviewer = ({
imageUploads,
multiple = true,
}: ImagePreviewerProps) => {
const { t } = useTranslationContext('ImagePreviewer');

const onClose: CustomMouseEvent = useCallback(
(id, event) => {
if (!id) return console.warn(`image.id of closed image was "null", this shouldn't happen`);
Expand All @@ -56,7 +59,7 @@ export const ImagePreviewer = ({
>
{image.state === 'failed' && (
<button
aria-label='Retry upload'
aria-label={t('aria/Retry upload')}
className='rfu-image-previewer__retry'
onClick={(event) => handleRetry?.(image.id, event)}
type='button'
Expand Down
36 changes: 20 additions & 16 deletions src/components/ReactFileUtilities/ImageUploadButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { PropsWithChildren } from 'react';

import { PictureIcon } from './icons';
import { UploadButton } from './UploadButton';
import { useTranslationContext } from '../../context';

export type ImageUploadButtonProps = {
handleFiles: (files: File[]) => void;
Expand All @@ -19,19 +20,22 @@ export const ImageUploadButton = ({
handleFiles,
children = <PictureIcon />,
resetOnChange = false,
}: PropsWithChildren<ImageUploadButtonProps>) => (
<div className='rfu-image-upload-button'>
<label>
<UploadButton
accept='image/*'
aria-label='Image input'
className='rfu-image-input'
disabled={disabled}
multiple={multiple}
onFileChange={handleFiles}
resetOnChange={resetOnChange}
/>
{children}
</label>
</div>
);
}: PropsWithChildren<ImageUploadButtonProps>) => {
const { t } = useTranslationContext('ImageUploadButton');
return (
<div className='rfu-image-upload-button'>
<label>
<UploadButton
accept='image/*'
aria-label={t('aria/Image input')}
className='rfu-image-input'
disabled={disabled}
multiple={multiple}
onFileChange={handleFiles}
resetOnChange={resetOnChange}
/>
{children}
</label>
</div>
);
};
5 changes: 3 additions & 2 deletions src/components/Reactions/ReactionsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { ReactEventHandler } from '../Message/types';
import type { DefaultStreamChatGenerics } from '../../types/types';
import type { ReactionOptions } from './reactionOptions';
import { ReactionsListModal } from './ReactionsListModal';
import { MessageContextValue } from '../../context';
import { MessageContextValue, useTranslationContext } from '../../context';
import { MAX_MESSAGE_REACTIONS_TO_FETCH } from '../Message/hooks';

export type ReactionsListProps<
Expand Down Expand Up @@ -37,6 +37,7 @@ const UnMemoizedReactionsList = <
const { handleFetchReactions, reverse = false, ...rest } = props;
const { existingReactions, hasReactions, totalReactionCount } = useProcessReactions(rest);
const [selectedReactionType, setSelectedReactionType] = useState<string | null>(null);
const { t } = useTranslationContext('ReactionsList');

const handleReactionButtonClick = (reactionType: string) => {
if (totalReactionCount > MAX_MESSAGE_REACTIONS_TO_FETCH) {
Expand All @@ -51,7 +52,7 @@ const UnMemoizedReactionsList = <
return (
<>
<div
aria-label='Reaction list'
aria-label={t('aria/Reaction list')}
className={clsx('str-chat__reaction-list str-chat__message-reactions-container', {
'str-chat__reaction-list--reverse': reverse,
})}
Expand Down
Loading