Skip to content

Commit

Permalink
[core] Add localization (#18219)
Browse files Browse the repository at this point in the history
  • Loading branch information
soltanloo authored and oliviertassinari committed Nov 16, 2019
1 parent 7875ae3 commit b7cb1c5
Show file tree
Hide file tree
Showing 24 changed files with 490 additions and 125 deletions.
3 changes: 3 additions & 0 deletions docs/pages/api/autocomplete.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
| <span class="prop-name">autoSelect</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If `true`, the selected option becomes the value of the input when the Autocomplete loses focus unless the user chooses a different option or changes the character string in the input. |
| <span class="prop-name">classes</span> | <span class="prop-type">object</span> | | Override or extend the styles applied to the component. See [CSS API](#css) below for more details. |
| <span class="prop-name">clearOnEscape</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If `true`, clear all values when the user presses escape and the popup is closed. |
| <span class="prop-name">clearText</span> | <span class="prop-type">string</span> | <span class="prop-default">'Clear'</span> | Override the default text for the *clear* icon button. |
| <span class="prop-name">closeIcon</span> | <span class="prop-type">node</span> | <span class="prop-default">&lt;CloseIcon fontSize="small" /></span> | The icon to display in place of the default close icon. |
| <span class="prop-name">closeText</span> | <span class="prop-type">string</span> | <span class="prop-default">'Close'</span> | Override the default text for the *close popup* icon button. |
| <span class="prop-name">debug</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If `true`, the popup will ignore the blur event if the input if filled. You can inspect the popup markup with your browser tools. Consider this option when you need to customize the component. |
| <span class="prop-name">defaultValue</span> | <span class="prop-type">any</span> | | The default input value. Use when the component is not controlled. |
| <span class="prop-name">disableClearable</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If `true`, the input can't be cleared. |
Expand Down Expand Up @@ -57,6 +59,7 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
| <span class="prop-name">onInputChange</span> | <span class="prop-type">func</span> | | Callback fired when the input value changes.<br><br>**Signature:**<br>`function(event: object, value: string) => void`<br>*event:* The event source of the callback.<br>*value:* null |
| <span class="prop-name">onOpen</span> | <span class="prop-type">func</span> | | Callback fired when the popup requests to be opened. Use in controlled mode (see open).<br><br>**Signature:**<br>`function(event: object) => void`<br>*event:* The event source of the callback. |
| <span class="prop-name">open</span> | <span class="prop-type">bool</span> | | Control the popup` open state. |
| <span class="prop-name">openText</span> | <span class="prop-type">string</span> | <span class="prop-default">'Open'</span> | Override the default text for the *open popup* icon button. |
| <span class="prop-name">options</span> | <span class="prop-type">array</span> | <span class="prop-default">[]</span> | Array of options. |
| <span class="prop-name">PaperComponent</span> | <span class="prop-type">elementType</span> | <span class="prop-default">Paper</span> | The component used to render the body of the popup. |
| <span class="prop-name">PopperComponent</span> | <span class="prop-type">elementType</span> | <span class="prop-default">Popper</span> | The component used to position the popup. |
Expand Down
2 changes: 2 additions & 0 deletions docs/pages/api/table-pagination.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ A `TableCell` based component for placing inside `TableFooter` for pagination.
|:-----|:-----|:--------|:------------|
| <span class="prop-name">ActionsComponent</span> | <span class="prop-type">elementType</span> | <span class="prop-default">TablePaginationActions</span> | The component used for displaying the actions. Either a string to use a DOM element or a component. |
| <span class="prop-name">backIconButtonProps</span> | <span class="prop-type">object</span> | | Props applied to the back arrow [`IconButton`](/api/icon-button/) component. |
| <span class="prop-name">backIconButtonText</span> | <span class="prop-type">string</span> | <span class="prop-default">'Previous page'</span> | Text label for the back arrow icon button. |
| <span class="prop-name">classes</span> | <span class="prop-type">object</span> | | Override or extend the styles applied to the component. See [CSS API](#css) below for more details. |
| <span class="prop-name">component</span> | <span class="prop-type">elementType</span> | <span class="prop-default">TableCell</span> | The component used for the root node. Either a string to use a DOM element or a component. |
| <span class="prop-name required">count&nbsp;*</span> | <span class="prop-type">number</span> | | The total number of rows. |
| <span class="prop-name">labelDisplayedRows</span> | <span class="prop-type">func</span> | <span class="prop-default">({ from, to, count }) =>`${from}-${to === -1 ? count : to} of ${count}`</span> | Customize the displayed rows label. |
| <span class="prop-name">labelRowsPerPage</span> | <span class="prop-type">node</span> | <span class="prop-default">'Rows per page:'</span> | Customize the rows per page label. Invoked with a `{ from, to, count, page }` object. |
| <span class="prop-name">nextIconButtonProps</span> | <span class="prop-type">object</span> | | Props applied to the next arrow [`IconButton`](/api/icon-button/) element. |
| <span class="prop-name">nextIconButtonText</span> | <span class="prop-type">string</span> | <span class="prop-default">'Next page'</span> | Text label for the next arrow icon button. |
| <span class="prop-name required">onChangePage&nbsp;*</span> | <span class="prop-type">func</span> | | Callback fired when the page is changed.<br><br>**Signature:**<br>`function(event: object, page: number) => void`<br>*event:* The event source of the callback.<br>*page:* The page selected. |
| <span class="prop-name">onChangeRowsPerPage</span> | <span class="prop-type">func</span> | | Callback fired when the number of rows per page is changed.<br><br>**Signature:**<br>`function(event: object) => void`<br>*event:* The event source of the callback. |
| <span class="prop-name required">page&nbsp;*</span> | <span class="prop-type">number</span> | | The zero-based index of the current page. |
Expand Down
14 changes: 14 additions & 0 deletions docs/pages/guides/localization.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';

const req = require.context('docs/src/pages/guides/localization', false, /\.(md|js|tsx)$/);
const reqSource = require.context(
'!raw-loader!../../src/pages/guides/localization',
false,
/\.(js|tsx)$/,
);
const reqPrefix = 'pages/guides/localization';

export default function Page() {
return <MarkdownDocs req={req} reqSource={reqSource} reqPrefix={reqPrefix} />;
}
1 change: 0 additions & 1 deletion docs/src/modules/components/MarkdownElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,6 @@ const styles = theme => ({
},
'& table': {
width: '100%',
display: 'block',
overflowX: 'auto',
WebkitOverflowScrolling: 'touch', // iOS momentum scrolling.
borderCollapse: 'collapse',
Expand Down
138 changes: 70 additions & 68 deletions docs/src/modules/components/ThemeContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,24 @@ import {
createMuiTheme,
darken,
} from '@material-ui/core/styles';
import { useSelector } from 'react-redux';
import useMediaQuery from '@material-ui/core/useMediaQuery';
import { enUS, zhCN, faIR, ruRU, ptBR, esES, frFR, deDE, jaJP } from '@material-ui/core/locale';
import { blue, pink } from '@material-ui/core/colors';
import { getCookie } from 'docs/src/modules/utils/helpers';
import { darkTheme, setPrismTheme } from 'docs/src/modules/components/prism';
import deepmerge from 'deepmerge';

const languageMap = {
en: enUS,
zh: zhCN,
fa: faIR,
ru: ruRU,
pt: ptBR,
es: esES,
fr: frFR,
de: deDE,
ja: jaJP,
};

export const themeColor = blue[700];

Expand All @@ -20,72 +33,59 @@ const themeInitialOptions = {
spacing: 8, // spacing unit
};

/**
* @typedef {import('@material-ui/core/src/styles/createMuiTheme').ThemeOptions} ThemeOptions
*
*
* @param {ThemeOptions} themeOptions
* @returns {ThemeOptions}
*/
function usingHighDensity(themeOptions) {
return deepmerge(themeOptions, {
props: {
MuiButton: {
size: 'small',
},
MuiFilledInput: {
margin: 'dense',
},
MuiFormControl: {
margin: 'dense',
},
MuiFormHelperText: {
margin: 'dense',
},
MuiIconButton: {
size: 'small',
},
MuiInputBase: {
margin: 'dense',
},
MuiInputLabel: {
margin: 'dense',
},
MuiListItem: {
dense: true,
},
MuiOutlinedInput: {
margin: 'dense',
},
MuiFab: {
size: 'small',
},
MuiTable: {
size: 'small',
},
MuiTextField: {
margin: 'dense',
},
MuiToolbar: {
variant: 'dense',
},
const highDensity = {
props: {
MuiButton: {
size: 'small',
},
overrides: {
MuiIconButton: {
sizeSmall: {
// minimal touch target hit spacing
marginLeft: 4,
marginRight: 4,
padding: 12,
},
MuiFilledInput: {
margin: 'dense',
},
MuiFormControl: {
margin: 'dense',
},
MuiFormHelperText: {
margin: 'dense',
},
MuiIconButton: {
size: 'small',
},
MuiInputBase: {
margin: 'dense',
},
MuiInputLabel: {
margin: 'dense',
},
MuiListItem: {
dense: true,
},
MuiOutlinedInput: {
margin: 'dense',
},
MuiFab: {
size: 'small',
},
MuiTable: {
size: 'small',
},
MuiTextField: {
margin: 'dense',
},
MuiToolbar: {
variant: 'dense',
},
},
overrides: {
MuiIconButton: {
sizeSmall: {
// minimal touch target hit spacing
marginLeft: 4,
marginRight: 4,
padding: 12,
},
},
});
}

function usingIdentity(themeOptions) {
return themeOptions;
}
},
};

export const DispatchContext = React.createContext(() => {
throw new Error('Forgot to wrap component in ThemeContext.Provider');
Expand Down Expand Up @@ -143,6 +143,7 @@ export function ThemeProvider(props) {
}
}, themeInitialOptions);

const userLanguage = useSelector(state => state.options.userLanguage);
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
const preferredType = prefersDarkMode ? 'dark' : 'light';
const { dense, direction, paletteColors, paletteType = preferredType, spacing } = themeOptions;
Expand Down Expand Up @@ -173,9 +174,8 @@ export function ThemeProvider(props) {
}, [direction]);

const theme = React.useMemo(() => {
const themeDecorator = dense ? usingHighDensity : usingIdentity;
const nextTheme = createMuiTheme(
themeDecorator({
{
direction,
nprogress: {
color: paletteType === 'light' ? '#000' : '#fff',
Expand All @@ -194,7 +194,9 @@ export function ThemeProvider(props) {
...paletteColors,
},
spacing,
}),
},
dense ? highDensity : null,
languageMap[userLanguage],
);

nextTheme.palette.background.level2 =
Expand All @@ -204,7 +206,7 @@ export function ThemeProvider(props) {
paletteType === 'light' ? '#fff' : nextTheme.palette.grey[900];

return nextTheme;
}, [dense, direction, paletteColors, paletteType, spacing]);
}, [dense, direction, paletteColors, paletteType, spacing, userLanguage]);

React.useEffect(() => {
// Expose the theme as a global variable so people can play with it.
Expand Down
1 change: 1 addition & 0 deletions docs/src/pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ const pages = [
{ pathname: '/guides/migration-v3', title: 'Migration From v3' },
{ pathname: '/guides/migration-v0x', title: 'Migration From v0.x' },
{ pathname: '/guides/testing' },
{ pathname: '/guides/localization' },
{ pathname: '/guides/right-to-left', title: 'Right-to-left' },
{ pathname: '/guides/flow' },
],
Expand Down
6 changes: 0 additions & 6 deletions docs/src/pages/components/tables/EnhancedTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,12 +342,6 @@ export default function EnhancedTable() {
count={rows.length}
rowsPerPage={rowsPerPage}
page={page}
backIconButtonProps={{
'aria-label': 'previous page',
}}
nextIconButtonProps={{
'aria-label': 'next page',
}}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
Expand Down
6 changes: 0 additions & 6 deletions docs/src/pages/components/tables/EnhancedTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -370,12 +370,6 @@ export default function EnhancedTable() {
count={rows.length}
rowsPerPage={rowsPerPage}
page={page}
backIconButtonProps={{
'aria-label': 'previous page',
}}
nextIconButtonProps={{
'aria-label': 'next page',
}}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
Expand Down
6 changes: 0 additions & 6 deletions docs/src/pages/components/tables/StickyHeadTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,6 @@ export default function StickyHeadTable() {
count={rows.length}
rowsPerPage={rowsPerPage}
page={page}
backIconButtonProps={{
'aria-label': 'previous page',
}}
nextIconButtonProps={{
'aria-label': 'next page',
}}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
Expand Down
6 changes: 0 additions & 6 deletions docs/src/pages/components/tables/StickyHeadTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,6 @@ export default function StickyHeadTable() {
count={rows.length}
rowsPerPage={rowsPerPage}
page={page}
backIconButtonProps={{
'aria-label': 'previous page',
}}
nextIconButtonProps={{
'aria-label': 'next page',
}}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
Expand Down
3 changes: 2 additions & 1 deletion docs/src/pages/customization/theming/theming.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,14 @@ The main point to understand is that the injected CSS is cached with the followi

## API

### `createMuiTheme(options) => theme`
### `createMuiTheme(options, ...args) => theme`

Generate a theme base on the options received.

#### Arguments

1. `options` (*Object*): Takes an incomplete theme object and adds the missing parts.
2. `...args` (*Array*): Deep merge the arguments with the about to be returned theme.

#### Returns

Expand Down
33 changes: 33 additions & 0 deletions docs/src/pages/guides/localization/Locales.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import TablePagination from '@material-ui/core/TablePagination';
import Rating from '@material-ui/lab/Rating';
import Autocomplete from '@material-ui/lab/Autocomplete';
import TextField from '@material-ui/core/TextField';
import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles';
import { zhCN } from '@material-ui/core/locale';

const theme = createMuiTheme({}, zhCN);

export default function Locales() {
return (
<div>
<ThemeProvider theme={theme}>
<TablePagination
count={20}
rowsPerPage={10}
page={1}
component="div"
onChangePage={() => {}}
/>
<Autocomplete
options={[]}
style={{ width: 300 }}
renderInput={params => (
<TextField {...params} label="自动完成" variant="outlined" fullWidth />
)}
/>
<Rating value={1} name="locales" />
</ThemeProvider>
</div>
);
}
33 changes: 33 additions & 0 deletions docs/src/pages/guides/localization/Locales.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import TablePagination from '@material-ui/core/TablePagination';
import Rating from '@material-ui/lab/Rating';
import Autocomplete from '@material-ui/lab/Autocomplete';
import TextField from '@material-ui/core/TextField';
import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles';
import { zhCN } from '@material-ui/core/locale';

const theme = createMuiTheme({}, zhCN);

export default function Locales() {
return (
<div>
<ThemeProvider theme={theme}>
<TablePagination
count={20}
rowsPerPage={10}
page={1}
component="div"
onChangePage={() => {}}
/>
<Autocomplete
options={[]}
style={{ width: 300 }}
renderInput={params => (
<TextField {...params} label="自动完成" variant="outlined" fullWidth />
)}
/>
<Rating value={1} name="locales" />
</ThemeProvider>
</div>
);
}
Loading

0 comments on commit b7cb1c5

Please sign in to comment.