Skip to content

refactor(i18n): respect lazy loaded translations #541

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

Merged
merged 12 commits into from
May 26, 2020
Merged
6 changes: 6 additions & 0 deletions .storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ module.exports = {
// You can change the configuration based on that.
// 'PRODUCTION' is used when building the static version of storybook.

config.module.rules.push({
test: /assets\/.*\.json$/,
use: 'file-loader',
type: 'javascript/auto'
});

const tsLoader = {
test: /\.tsx?$/,
include: PATHS.packages,
Expand Down
6 changes: 3 additions & 3 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ const ThemeContainer = ({ theme, contentDensity, children, direction }) => {
}
}, [contentDensity]);

useEffect(() => {
document.querySelector('html').setAttribute('dir', direction.toLowerCase());
}, [direction]);
// useEffect(() => {
// document.querySelector('html').setAttribute('dir', direction.toLowerCase());
// }, [direction]);

useEffect(() => {
setTheme(theme);
Expand Down
32 changes: 26 additions & 6 deletions packages/base/src/hooks/useI18nBundle.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,40 @@
import { fetchI18nBundle, getI18nBundle } from '@ui5/webcomponents-base/dist/i18nBundle';
import { useEffect, useState } from 'react';

type TextWithDefault = { key: string; defaultText: string };
type TextWithPlaceholders = [TextWithDefault, ...string[]];

interface I18nBundle {
getText: (textObj: { key: string; defaultText: string }, ...args: any) => string;
getText: (textObj: TextWithDefault, ...args: any) => string;
}

export const useI18nBundle = (bundleName): I18nBundle => {
const [bundle, setBundle] = useState(getI18nBundle(bundleName));
const resolveTranslations = (bundle, texts) => {
return texts.map((text) => {
if (Array.isArray(text)) {
const [key, ...replacements] = text;
return bundle.getText(key, replacements);
}
return bundle.getText(text);
});
};

export const useI18nText = (bundleName: string, ...texts: (TextWithDefault | TextWithPlaceholders)[]): string[] => {
const i18nBundle: I18nBundle = getI18nBundle(bundleName);
const [translations, setTranslations] = useState(resolveTranslations(i18nBundle, texts));

useEffect(() => {
const fetchAndLoadBundle = async () => {
await fetchI18nBundle(bundleName);
setBundle(getI18nBundle(bundleName));
setTranslations((prev) => {
const next = resolveTranslations(i18nBundle, texts);
if (prev.length === next.length && prev.every((translation, index) => next[index] === translation)) {
return prev;
}
return next;
});
};
fetchAndLoadBundle();
}, []);
}, [fetchI18nBundle, bundleName, texts]);

return bundle;
return translations;
};
4 changes: 2 additions & 2 deletions packages/base/src/lib/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useConsolidatedRef } from '../hooks/useConsolidatedRef';
import { useI18nBundle } from '../hooks/useI18nBundle';
import { useI18nText } from '../hooks/useI18nBundle';
import { usePassThroughHtmlProps } from '../hooks/usePassThroughHtmlProps';
import { useViewportRange } from '../hooks/useViewportRange';

export { useConsolidatedRef, usePassThroughHtmlProps, useViewportRange, useI18nBundle };
export { useConsolidatedRef, usePassThroughHtmlProps, useViewportRange, useI18nText };
8 changes: 4 additions & 4 deletions packages/main/src/components/AnalyticalCardHeader/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createComponentStyles } from '@ui5/webcomponents-react-base/lib/createComponentStyles';
import { useI18nBundle, usePassThroughHtmlProps } from '@ui5/webcomponents-react-base/lib/hooks';
import { useI18nText, usePassThroughHtmlProps } from '@ui5/webcomponents-react-base/lib/hooks';
import { StyleClassHelper } from '@ui5/webcomponents-react-base/lib/StyleClassHelper';
import { enrichEventWithDetails } from '@ui5/webcomponents-react-base/lib/Utils';
import { DEVIATION, TARGET } from '@ui5/webcomponents-react/dist/assets/i18n/i18n-defaults';
Expand Down Expand Up @@ -126,7 +126,7 @@ export const AnalyticalCardHeader: FC<AnalyticalCardHeaderPropTypes> = forwardRe

const passThroughProps = usePassThroughHtmlProps(props, ['onHeaderPress']);

const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
const [targetText, deviationText] = useI18nText('@ui5/webcomponents-react', TARGET, DEVIATION);

return (
<div
Expand Down Expand Up @@ -172,7 +172,7 @@ export const AnalyticalCardHeader: FC<AnalyticalCardHeaderPropTypes> = forwardRe
className={classes.targetAndDeviationColumn}
wrap={FlexBoxWrap.NoWrap}
>
<span>{i18nBundle.getText(TARGET)}</span>
<span>{targetText}</span>
<span className={classes.targetAndDeviationValue}>{target}</span>
</FlexBox>
)}
Expand All @@ -182,7 +182,7 @@ export const AnalyticalCardHeader: FC<AnalyticalCardHeaderPropTypes> = forwardRe
className={classes.targetAndDeviationColumn}
wrap={FlexBoxWrap.NoWrap}
>
<span>{i18nBundle.getText(DEVIATION)}</span>
<span>{deviationText}</span>
<span className={classes.targetAndDeviationValue}>{deviation}</span>
</FlexBox>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import '@ui5/webcomponents-icons/dist/icons/decline';
import { useI18nBundle } from '@ui5/webcomponents-react-base/lib/hooks';
import { useI18nText } from '@ui5/webcomponents-react-base/lib/hooks';
import { ThemingParameters } from '@ui5/webcomponents-react-base/lib/ThemingParameters';
import { enrichEventWithDetails } from '@ui5/webcomponents-react-base/lib/Utils';
import {
Expand Down Expand Up @@ -38,7 +38,14 @@ export const ColumnHeaderModal = forwardRef((props: ColumnHeaderModalProperties,

const { Filter } = column;

const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
const [clearSortingText, sortAscendingText, sortDescendingText, groupText, ungroupText] = useI18nText(
'@ui5/webcomponents-react',
CLEAR_SORTING,
SORT_ASCENDING,
SORT_DESCENDING,
GROUP,
UNGROUP
);

const handleSort = useCallback(
(e) => {
Expand Down Expand Up @@ -112,22 +119,22 @@ export const ColumnHeaderModal = forwardRef((props: ColumnHeaderModalProperties,
<List onItemClick={handleSort}>
{isSortedAscending && (
<StandardListItem type={ListItemTypes.Active} icon="decline" data-sort="clear">
{i18nBundle.getText(CLEAR_SORTING)}
{clearSortingText}
</StandardListItem>
)}
{showSort && !isSortedAscending && (
<StandardListItem type={ListItemTypes.Active} icon="sort-ascending" data-sort="asc">
{i18nBundle.getText(SORT_ASCENDING)}
{sortAscendingText}
</StandardListItem>
)}
{showSort && !isSortedDescending && (
<StandardListItem type={ListItemTypes.Active} icon="sort-descending" data-sort="desc">
{i18nBundle.getText(SORT_DESCENDING)}
{sortDescendingText}
</StandardListItem>
)}
{isSortedDescending && (
<StandardListItem type={ListItemTypes.Active} icon="decline" data-sort="clear">
{i18nBundle.getText(CLEAR_SORTING)}
{clearSortingText}
</StandardListItem>
)}
{showFilter && !column.isGrouped && (
Expand All @@ -145,7 +152,7 @@ export const ColumnHeaderModal = forwardRef((props: ColumnHeaderModalProperties,
)}
{showGroup && (
<StandardListItem type={ListItemTypes.Active} icon="group-2" data-sort={'group'}>
{i18nBundle.getText(column.isGrouped ? UNGROUP : GROUP)}
{column.isGrouped ? ungroupText : groupText}
</StandardListItem>
)}
</List>
Expand Down
39 changes: 26 additions & 13 deletions packages/main/src/components/FilterBar/FilterDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import '@ui5/webcomponents-icons/dist/icons/search';
import { createComponentStyles } from '@ui5/webcomponents-react-base/lib/createComponentStyles';
import { useI18nBundle } from '@ui5/webcomponents-react-base/lib/hooks';
import { useI18nText } from '@ui5/webcomponents-react-base/lib/hooks';
import { enrichEventWithDetails } from '@ui5/webcomponents-react-base/lib/Utils';
import {
BASIC,
Expand Down Expand Up @@ -59,7 +59,24 @@ export const FilterDialog = (props) => {
const dialogRefs = useRef({});
const dialogRef = useRef();

const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
const [
basicText,
cancelText,
clearText,
restoreText,
saveText,
searchForFiltersText,
showOnFilterBarText
] = useI18nText(
'@ui5/webcomponents-react',
BASIC,
CANCEL,
CLEAR,
RESTORE,
SAVE,
SEARCH_FOR_FILTERS,
SHOW_ON_FILTER_BAR
);

useEffect(() => {
if (open) {
Expand Down Expand Up @@ -132,11 +149,11 @@ export const FilterDialog = (props) => {
Go
</Button>
)}
{showClearButton && <Button onClick={handleClearFilters}>{i18nBundle.getText(CLEAR)}</Button>}
{showRestoreButton && <Button onClick={handleRestore}>{i18nBundle.getText(RESTORE)}</Button>}
<Button onClick={handleSave}>{i18nBundle.getText(SAVE)}</Button>
{showClearButton && <Button onClick={handleClearFilters}>{clearText}</Button>}
{showRestoreButton && <Button onClick={handleRestore}>{restoreText}</Button>}
<Button onClick={handleSave}>{saveText}</Button>
<Button design={ButtonDesign.Transparent} onClick={handleCancel}>
{i18nBundle.getText(CANCEL)}
{cancelText}
</Button>
</FlexBox>
),
Expand All @@ -162,11 +179,7 @@ export const FilterDialog = (props) => {
<FlexBox direction={FlexBoxDirection.Column} className={classes.header}>
<Title level={TitleLevel.H4}>Filters</Title>
{showSearch && (
<Input
placeholder={i18nBundle.getText(SEARCH_FOR_FILTERS)}
onInput={handleSearch}
icon={<Icon name="search" />}
/>
<Input placeholder={searchForFiltersText} onInput={handleSearch} icon={<Icon name="search" />} />
)}
</FlexBox>
),
Expand Down Expand Up @@ -244,9 +257,9 @@ export const FilterDialog = (props) => {
<div className={classes.groupContainer} key={item}>
<FlexBox justifyContent={FlexBoxJustifyContent.SpaceBetween} alignItems={FlexBoxAlignItems.Center}>
<Title level={TitleLevel.H5} className={index === 0 ? classes.groupTitle : ''}>
{item === 'default' ? i18nBundle.getText(BASIC) : item}
{item === 'default' ? basicText : item}
</Title>
{index === 0 && <Text wrapping={false}>{i18nBundle.getText(SHOW_ON_FILTER_BAR)}</Text>}
{index === 0 && <Text wrapping={false}>{showOnFilterBarText}</Text>}
</FlexBox>
<div className={classes.filters}>{filters}</div>
</div>
Expand Down
22 changes: 15 additions & 7 deletions packages/main/src/components/FilterBar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createComponentStyles } from '@ui5/webcomponents-react-base/lib/createComponentStyles';
import { useI18nBundle } from '@ui5/webcomponents-react-base/lib/hooks';
import { useI18nText } from '@ui5/webcomponents-react-base/lib/hooks';
import { StyleClassHelper } from '@ui5/webcomponents-react-base/lib/StyleClassHelper';
import { usePassThroughHtmlProps } from '@ui5/webcomponents-react-base/lib/usePassThroughHtmlProps';
import { enrichEventWithDetails } from '@ui5/webcomponents-react-base/lib/Utils';
Expand Down Expand Up @@ -117,7 +117,15 @@ const FilterBar: FC<FilterBarPropTypes> = forwardRef((props: FilterBarPropTypes,
const [toggledFilters, setToggledFilters] = useState({});
const prevVisibleInFilterBarProps = useRef({});

const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
const [clearText, restoreText, showFilterBarText, hideFilterBarText, goText, filtersText] = useI18nText(
'@ui5/webcomponents-react',
CLEAR,
RESTORE,
SHOW_FILTER_BAR,
HIDE_FILTER_BAR,
GO,
FILTERS
);

useEffect(() => {
if (showFilterConfiguration) {
Expand Down Expand Up @@ -337,20 +345,20 @@ const FilterBar: FC<FilterBarPropTypes> = forwardRef((props: FilterBarPropTypes,
<div className={classes.headerRowRight}>
{showClearOnFB && (
<Button onClick={onClear} design={ButtonDesign.Transparent}>
{i18nBundle.getText(CLEAR)}
{clearText}
</Button>
)}
{showRestoreOnFB && (
<Button onClick={handleFBRestore} design={ButtonDesign.Transparent}>
{i18nBundle.getText(RESTORE)}
{restoreText}
</Button>
)}
<Button onClick={handleToggle} design={ButtonDesign.Transparent} className={classes.showFiltersBtn}>
{showFilters ? i18nBundle.getText(HIDE_FILTER_BAR) : i18nBundle.getText(SHOW_FILTER_BAR)}
{showFilters ? hideFilterBarText : showFilterBarText}
</Button>
{showFilterConfiguration && (
<Button onClick={handleDialogOpen}>
{`${i18nBundle.getText(FILTERS)}${
{`${filtersText}${
activeFiltersCount && parseInt(activeFiltersCount as string) > 0
? ` (${activeFiltersCount})`
: ''
Expand All @@ -359,7 +367,7 @@ const FilterBar: FC<FilterBarPropTypes> = forwardRef((props: FilterBarPropTypes,
)}
{showGoOnFB && (
<Button onClick={onGo} design={ButtonDesign.Emphasized}>
{i18nBundle.getText(GO)}
{goText}
</Button>
)}
</div>
Expand Down
6 changes: 3 additions & 3 deletions packages/main/src/components/Loader/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createComponentStyles } from '@ui5/webcomponents-react-base/lib/createComponentStyles';
import { useI18nBundle } from '@ui5/webcomponents-react-base/lib/hooks';
import { StyleClassHelper } from '@ui5/webcomponents-react-base/lib/StyleClassHelper';
import { usePassThroughHtmlProps } from '@ui5/webcomponents-react-base/lib/usePassThroughHtmlProps';
import { useI18nText } from '@ui5/webcomponents-react-base/lib/hooks';
import { PLEASE_WAIT } from '@ui5/webcomponents-react/dist/assets/i18n/i18n-defaults';
import { LoaderType } from '@ui5/webcomponents-react/lib/LoaderType';
import React, { CSSProperties, FC, forwardRef, RefObject, useEffect, useMemo, useState } from 'react';
Expand Down Expand Up @@ -55,7 +55,7 @@ const Loader: FC<LoaderProps> = forwardRef((props: LoaderProps, ref: RefObject<H

const passThroughProps = usePassThroughHtmlProps(props);

const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
const [pleaseWait] = useI18nText('@ui5/webcomponents-react', PLEASE_WAIT);

if (!isVisible) {
return null;
Expand All @@ -68,7 +68,7 @@ const Loader: FC<LoaderProps> = forwardRef((props: LoaderProps, ref: RefObject<H
data-component-name="Loader"
aria-busy="true"
role="progressbar"
title={tooltip || i18nBundle.getText(PLEASE_WAIT)}
title={tooltip || pleaseWait}
slot={slot}
style={inlineStyles}
{...passThroughProps}
Expand Down
15 changes: 7 additions & 8 deletions packages/main/src/components/MessageBox/MessageBox.jss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@ const style = {
verticalAlign: 'middle'
}
},
// justifyContent: 'center',
padding: '0.25rem 1rem',
boxSizing: 'border-box',
borderBottom: `1px solid var(--messageBoxBorderColor)`,
color: ThemingParameters.sapContent_LabelColor,
fontSize: '1rem',
'& ui5-icon:first-child': {
padding: '0 0.25rem',
width: '1rem',
height: '1rem'
},
'&[data-type="Error"]': {
'--sapPageFooter_BorderColor': ThemingParameters.sapErrorBorderColor,
'--messageBoxBorderColor': ThemingParameters.sapErrorBorderColor,
Expand Down Expand Up @@ -63,11 +67,6 @@ const style = {
}
}
},
icon: {
marginRight: '0.5rem',
fontSize: '1rem',
width: '1rem'
},
content: {
padding: '1rem'
},
Expand All @@ -77,8 +76,8 @@ const style = {
alignItems: 'center',
justifyContent: 'flex-end',
padding: '0 0.5rem',
'& >*:not(:last-child)': {
marginRight: '0.5rem'
'& > *': {
margin: '0 0.25rem'
},
'& > ui5-button': {
display: 'flex'
Expand Down
Loading