Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

Commit

Permalink
feat(rish): translations for widgets (#3638)
Browse files Browse the repository at this point in the history
### [FX-1708](https://algolia.atlassian.net/browse/FX-1708)

**Summary**

- Make components in `widgets` accept an *optional* `translations` prop
and forward it to the UI
- All components using `ShowMoreButton` can translate this button too
- Added translations to `RefinementList` for its internal searchbox and
for 'no results'

**Result**

Added tests to each widget to check if the translation is taken into
account, used mostly `getBy*` rather than snapshots to create less noise
in tests

Co-authored-by: Sarah Dayan <5370675+sarahdayan@users.noreply.github.com>
  • Loading branch information
aymeric-giraudet and sarahdayan authored Sep 29, 2022
1 parent 06cad33 commit 63b506f
Show file tree
Hide file tree
Showing 39 changed files with 714 additions and 172 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@
},
{
"path": "packages/react-instantsearch-hooks-web/dist/umd/ReactInstantSearchHooksDOM.min.js",
"maxSize": "49.50 kB"
"maxSize": "49.75 kB"
},
{
"path": "packages/react-instantsearch-dom/dist/umd/ReactInstantSearchDOM.min.js",
Expand Down
4 changes: 2 additions & 2 deletions packages/react-instantsearch-hooks-web/src/ui/Breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export type BreadcrumbTranslations = {
/**
* The label of the root element
*/
root: string;
rootElementText: string;
};

export type BreadcrumbClassNames = {
Expand Down Expand Up @@ -100,7 +100,7 @@ export function Breadcrumb({
onClick={handleClick(null)}
className={cx('ais-Breadcrumb-link', classNames.link)}
>
{translations.root}
{translations.rootElementText}
</a>
</li>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export type ClearRefinementsTranslations = {
/**
* The label of the button
*/
resetLabel: string;
resetButtonText: string;
};

export type ClearRefinementsProps = React.ComponentProps<'div'> &
Expand Down Expand Up @@ -55,7 +55,7 @@ export function ClearRefinements({
)
)}
>
{translations.resetLabel}
{translations.resetButtonText}
</button>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { cx } from './lib/cx';
import { isModifierClick } from './lib/isModifierClick';
import { ShowMoreButton } from './ShowMoreButton';

import type { ShowMoreButtonTranslations } from './ShowMoreButton';
import type { useHierarchicalMenu } from 'react-instantsearch-hooks';

type HierarchicalMenuClassNames = {
Expand Down Expand Up @@ -73,8 +74,11 @@ export type HierarchicalMenuProps = React.ComponentProps<'div'> &
canToggleShowMore: boolean;
onToggleShowMore: () => void;
isShowingMore: boolean;
translations: ShowMoreButtonTranslations;
};

export type HierarchicalMenuTranslations = ShowMoreButtonTranslations;

function HierarchicalList({
className,
classNames = {},
Expand Down Expand Up @@ -146,6 +150,7 @@ export function HierarchicalMenu({
canToggleShowMore,
onToggleShowMore,
isShowingMore,
translations,
...props
}: HierarchicalMenuProps) {
return (
Expand Down Expand Up @@ -179,6 +184,7 @@ export function HierarchicalMenu({
disabled={!canToggleShowMore}
onClick={onToggleShowMore}
isShowingMore={isShowingMore}
translations={translations}
/>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ export type InfiniteHitsClassNames = {
};

export type InfiniteHitsTranslations = {
showPrevious: string;
showMore: string;
showPreviousButtonText: string;
showMoreButtonText: string;
};

function DefaultHitComponent({ hit }: { hit: Hit }) {
Expand Down Expand Up @@ -105,7 +105,7 @@ export function InfiniteHits<THit extends Hit>({
onClick={onShowPrevious}
disabled={isFirstPage}
>
{translations.showPrevious}
{translations.showPreviousButtonText}
</button>
)}
<ol className={cx('ais-InfiniteHits-list', classNames.list)}>
Expand All @@ -131,7 +131,7 @@ export function InfiniteHits<THit extends Hit>({
onClick={onShowMore}
disabled={isLastPage}
>
{translations.showMore}
{translations.showMoreButtonText}
</button>
</div>
);
Expand Down
6 changes: 6 additions & 0 deletions packages/react-instantsearch-hooks-web/src/ui/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';
import { cx } from './lib/cx';
import { ShowMoreButton } from './ShowMoreButton';

import type { ShowMoreButtonTranslations } from './ShowMoreButton';
import type { CreateURL } from 'instantsearch.js';
import type { MenuItem } from 'instantsearch.js/es/connectors/menu/connectMenu';

Expand All @@ -15,6 +16,7 @@ export type MenuProps = React.ComponentProps<'div'> & {
isShowingMore: boolean;
createURL: CreateURL<MenuItem['value']>;
onRefine: (item: MenuItem) => void;
translations: MenuTranslations;
};

export type MenuCSSClasses = {
Expand Down Expand Up @@ -60,6 +62,8 @@ export type MenuCSSClasses = {
disabledShowMore: string;
};

export type MenuTranslations = ShowMoreButtonTranslations;

export function Menu({
items,
classNames = {},
Expand All @@ -69,6 +73,7 @@ export function Menu({
isShowingMore,
createURL,
onRefine,
translations,
...props
}: MenuProps) {
return (
Expand Down Expand Up @@ -122,6 +127,7 @@ export function Menu({
disabled={!canToggleShowMore}
onClick={onToggleShowMore}
isShowingMore={isShowingMore}
translations={translations}
/>
)}
</div>
Expand Down
54 changes: 34 additions & 20 deletions packages/react-instantsearch-hooks-web/src/ui/Pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,58 @@ import { isModifierClick } from './lib/isModifierClick';

import type { CreateURL } from 'instantsearch.js';

export type PageItemTextOptions = {
/**
* The page number to be displayed.
*/
currentPage: number;
/**
* The total number of pages.
*/
nbPages: number;
};

export type PaginationTranslations = {
/**
* The label for the first page's button.
*/
first: string;
firstPageItemText: string;
/**
* The label for the previous page's button.
*/
previous: string;
previousPageItemText: string;
/**
* The label for the next page's button.
*/
next: string;
nextPageItemText: string;
/**
* The label for the last page's button.
*/
last: string;
lastPageItemText: string;
/**
* The label for a page's button.
*/
page(currentPage: number): string;
pageItemText(options: PageItemTextOptions): string;
/**
* The accessible label for the first page's button.
*/
ariaFirst: string;
firstPageItemAriaLabel: string;
/**
* The accessible label for the previous page's button.
*/
ariaPrevious: string;
previousPageItemAriaLabel: string;
/**
* The accessible label for the next page's button.
*/
ariaNext: string;
nextPageItemAriaLabel: string;
/**
* The accessible label for the last page's button.
*/
ariaLast: string;
lastPageItemAriaLabel: string;
/**
* The accessible label for a page's button.
*/
ariaPage(currentPage: number): string;
pageItemAriaLabel(options: PageItemTextOptions): string;
};

export type PaginationProps = React.ComponentProps<'div'> & {
Expand Down Expand Up @@ -155,11 +166,11 @@ export function Pagination({
classNames.firstPageItem
)}
classNames={classNames}
aria-label={translations.ariaFirst}
aria-label={translations.firstPageItemAriaLabel}
href={createURL(firstPageIndex)}
onClick={() => onNavigate(firstPageIndex)}
>
{translations.first}
{translations.firstPageItemText}
</PaginationItem>
)}
{showPrevious && (
Expand All @@ -170,11 +181,11 @@ export function Pagination({
classNames.previousPageItem
)}
classNames={classNames}
aria-label={translations.ariaPrevious}
aria-label={translations.previousPageItemAriaLabel}
href={createURL(previousPageIndex)}
onClick={() => onNavigate(previousPageIndex)}
>
{translations.previous}
{translations.previousPageItemText}
</PaginationItem>
)}
{pages.map((page) => {
Expand All @@ -189,11 +200,14 @@ export function Pagination({
cx('ais-Pagination-item--selected', classNames.selectedItem)
)}
classNames={classNames}
aria-label={translations.ariaPage(page + 1)}
aria-label={translations.pageItemAriaLabel({
currentPage: page + 1,
nbPages,
})}
href={createURL(page)}
onClick={() => onNavigate(page)}
>
{translations.page(page + 1)}
{translations.pageItemText({ currentPage: page + 1, nbPages })}
</PaginationItem>
);
})}
Expand All @@ -205,11 +219,11 @@ export function Pagination({
classNames.nextPageItem
)}
classNames={classNames}
aria-label={translations.ariaNext}
aria-label={translations.nextPageItemAriaLabel}
href={createURL(nextPageIndex)}
onClick={() => onNavigate(nextPageIndex)}
>
{translations.next}
{translations.nextPageItemText}
</PaginationItem>
)}
{showLast && (
Expand All @@ -220,11 +234,11 @@ export function Pagination({
classNames.lastPageItem
)}
classNames={classNames}
aria-label={translations.ariaLast}
aria-label={translations.lastPageItemAriaLabel}
href={createURL(lastPageIndex)}
onClick={() => onNavigate(lastPageIndex)}
>
{translations.last}
{translations.lastPageItemText}
</PaginationItem>
)}
</ul>
Expand Down
8 changes: 4 additions & 4 deletions packages/react-instantsearch-hooks-web/src/ui/RangeInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ export type RangeInputTranslations = {
/**
* The label of the separator, between the minimum and maximum inputs
*/
separator: string;
separatorElementText: string;
/**
* The label of the submit button
*/
submit: string;
submitButtonText: string;
};

// if the default value is undefined, React considers the component uncontrolled initially, which we don't want 0 or NaN as the default value
Expand Down Expand Up @@ -138,7 +138,7 @@ export function RangeInput({
/>
</label>
<span className={cx('ais-RangeInput-separator', classNames.separator)}>
{translations.separator}
{translations.separatorElementText}
</span>
<label className={cx('ais-RangeInput-label', classNames.label)}>
<input
Expand All @@ -164,7 +164,7 @@ export function RangeInput({
className={cx('ais-RangeInput-submit', classNames.submit)}
type="submit"
>
{translations.submit}
{translations.submitButtonText}
</button>
</form>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Highlight } from './Highlight';
import { cx } from './lib/cx';
import { ShowMoreButton } from './ShowMoreButton';

import type { ShowMoreButtonTranslations } from './ShowMoreButton';
import type { RefinementListItem } from 'instantsearch.js/es/connectors/refinement-list/connectRefinementList';

export type RefinementListProps = React.ComponentProps<'div'> & {
Expand All @@ -19,6 +20,7 @@ export type RefinementListProps = React.ComponentProps<'div'> & {
onToggleShowMore: () => void;
isShowingMore: boolean;
classNames?: Partial<RefinementListClassNames>;
translations: RefinementListTranslations;
};

export type RefinementListClassNames = {
Expand Down Expand Up @@ -76,6 +78,8 @@ export type RefinementListClassNames = {
disabledShowMore: string;
};

export type RefinementListTranslations = ShowMoreButtonTranslations;

export function RefinementList({
canRefine,
items,
Expand All @@ -89,6 +93,7 @@ export function RefinementList({
isShowingMore,
className,
classNames = {},
translations,
...props
}: RefinementListProps) {
return (
Expand Down Expand Up @@ -185,6 +190,7 @@ export function RefinementList({
disabled={!canToggleShowMore}
onClick={onToggleShowMore}
isShowingMore={isShowingMore}
translations={translations}
/>
)}
</div>
Expand Down
8 changes: 4 additions & 4 deletions packages/react-instantsearch-hooks-web/src/ui/SearchBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ export type SearchBoxTranslations = {
/**
* The alternative text of the submit button.
*/
submitTitle: string;
submitButtonTitle: string;
/**
* The alternative text of the reset button.
*/
resetTitle: string;
resetButtonTitle: string;
};

export type SearchBoxProps = Omit<
Expand Down Expand Up @@ -202,14 +202,14 @@ export function SearchBox({
<button
className={cx('ais-SearchBox-submit', classNames.submit)}
type="submit"
title={translations.submitTitle}
title={translations.submitButtonTitle}
>
<SubmitIcon classNames={classNames} />
</button>
<button
className={cx('ais-SearchBox-reset', classNames.reset)}
type="reset"
title={translations.resetTitle}
title={translations.resetButtonTitle}
hidden={value.length === 0 || isSearchStalled}
>
<ResetIcon classNames={classNames} />
Expand Down
Loading

0 comments on commit 63b506f

Please sign in to comment.