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

[core] Add localization #18219

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
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