diff --git a/docs/pages/api/autocomplete.md b/docs/pages/api/autocomplete.md
index d626ef39652cef..3db98d9d9ddb28 100644
--- a/docs/pages/api/autocomplete.md
+++ b/docs/pages/api/autocomplete.md
@@ -29,7 +29,9 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
| autoSelect | bool | false | 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. |
| classes | object | | Override or extend the styles applied to the component. See [CSS API](#css) below for more details. |
| clearOnEscape | bool | false | If `true`, clear all values when the user presses escape and the popup is closed. |
+| clearText | string | 'Clear' | Override the default text for the *clear* icon button. |
| closeIcon | node | <CloseIcon fontSize="small" /> | The icon to display in place of the default close icon. |
+| closeText | string | 'Close' | Override the default text for the *close popup* icon button. |
| debug | bool | false | 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. |
| defaultValue | any | | The default input value. Use when the component is not controlled. |
| disableClearable | bool | false | If `true`, the input can't be cleared. |
@@ -57,6 +59,7 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
| onInputChange | func | | Callback fired when the input value changes.
**Signature:**
`function(event: object, value: string) => void`
*event:* The event source of the callback.
*value:* null |
| onOpen | func | | Callback fired when the popup requests to be opened. Use in controlled mode (see open).
**Signature:**
`function(event: object) => void`
*event:* The event source of the callback. |
| open | bool | | Control the popup` open state. |
+| openText | string | 'Open' | Override the default text for the *open popup* icon button. |
| options | array | [] | Array of options. |
| PaperComponent | elementType | Paper | The component used to render the body of the popup. |
| PopperComponent | elementType | Popper | The component used to position the popup. |
diff --git a/docs/pages/api/table-pagination.md b/docs/pages/api/table-pagination.md
index 0d3907117e0e15..da4de808f0402c 100644
--- a/docs/pages/api/table-pagination.md
+++ b/docs/pages/api/table-pagination.md
@@ -26,12 +26,14 @@ A `TableCell` based component for placing inside `TableFooter` for pagination.
|:-----|:-----|:--------|:------------|
| ActionsComponent | elementType | TablePaginationActions | The component used for displaying the actions. Either a string to use a DOM element or a component. |
| backIconButtonProps | object | | Props applied to the back arrow [`IconButton`](/api/icon-button/) component. |
+| backIconButtonText | string | 'Previous page' | Text label for the back arrow icon button. |
| classes | object | | Override or extend the styles applied to the component. See [CSS API](#css) below for more details. |
| component | elementType | TableCell | The component used for the root node. Either a string to use a DOM element or a component. |
| count * | number | | The total number of rows. |
| labelDisplayedRows | func | ({ from, to, count }) =>`${from}-${to === -1 ? count : to} of ${count}` | Customize the displayed rows label. |
| labelRowsPerPage | node | 'Rows per page:' | Customize the rows per page label. Invoked with a `{ from, to, count, page }` object. |
| nextIconButtonProps | object | | Props applied to the next arrow [`IconButton`](/api/icon-button/) element. |
+| nextIconButtonText | string | 'Next page' | Text label for the next arrow icon button. |
| onChangePage * | func | | Callback fired when the page is changed.
**Signature:**
`function(event: object, page: number) => void`
*event:* The event source of the callback.
*page:* The page selected. |
| onChangeRowsPerPage | func | | Callback fired when the number of rows per page is changed.
**Signature:**
`function(event: object) => void`
*event:* The event source of the callback. |
| page * | number | | The zero-based index of the current page. |
diff --git a/docs/pages/guides/localization.js b/docs/pages/guides/localization.js
new file mode 100644
index 00000000000000..89861be719ea5b
--- /dev/null
+++ b/docs/pages/guides/localization.js
@@ -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 ;
+}
diff --git a/docs/src/modules/components/MarkdownElement.js b/docs/src/modules/components/MarkdownElement.js
index 5e02f77131e33d..e0b611f2431534 100644
--- a/docs/src/modules/components/MarkdownElement.js
+++ b/docs/src/modules/components/MarkdownElement.js
@@ -215,7 +215,6 @@ const styles = theme => ({
},
'& table': {
width: '100%',
- display: 'block',
overflowX: 'auto',
WebkitOverflowScrolling: 'touch', // iOS momentum scrolling.
borderCollapse: 'collapse',
diff --git a/docs/src/modules/components/ThemeContext.js b/docs/src/modules/components/ThemeContext.js
index 383a47d90482db..9ce32289b84bf9 100644
--- a/docs/src/modules/components/ThemeContext.js
+++ b/docs/src/modules/components/ThemeContext.js
@@ -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];
@@ -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');
@@ -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;
@@ -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',
@@ -194,7 +194,9 @@ export function ThemeProvider(props) {
...paletteColors,
},
spacing,
- }),
+ },
+ dense ? highDensity : null,
+ languageMap[userLanguage],
);
nextTheme.palette.background.level2 =
@@ -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.
diff --git a/docs/src/pages.js b/docs/src/pages.js
index 340c7361c4ca7c..03d0b7dc2d2322 100644
--- a/docs/src/pages.js
+++ b/docs/src/pages.js
@@ -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' },
],
diff --git a/docs/src/pages/components/tables/EnhancedTable.js b/docs/src/pages/components/tables/EnhancedTable.js
index f1517a71619ec5..639b2c2ced4adf 100644
--- a/docs/src/pages/components/tables/EnhancedTable.js
+++ b/docs/src/pages/components/tables/EnhancedTable.js
@@ -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}
/>
diff --git a/docs/src/pages/components/tables/EnhancedTable.tsx b/docs/src/pages/components/tables/EnhancedTable.tsx
index c210ca5a84fb1d..0af02705ca14b9 100644
--- a/docs/src/pages/components/tables/EnhancedTable.tsx
+++ b/docs/src/pages/components/tables/EnhancedTable.tsx
@@ -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}
/>
diff --git a/docs/src/pages/components/tables/StickyHeadTable.js b/docs/src/pages/components/tables/StickyHeadTable.js
index 3890ed7999c591..3c53bc6fa4e06d 100644
--- a/docs/src/pages/components/tables/StickyHeadTable.js
+++ b/docs/src/pages/components/tables/StickyHeadTable.js
@@ -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}
/>
diff --git a/docs/src/pages/components/tables/StickyHeadTable.tsx b/docs/src/pages/components/tables/StickyHeadTable.tsx
index e2ae21519a8910..dfa5dece803272 100644
--- a/docs/src/pages/components/tables/StickyHeadTable.tsx
+++ b/docs/src/pages/components/tables/StickyHeadTable.tsx
@@ -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}
/>
diff --git a/docs/src/pages/customization/theming/theming.md b/docs/src/pages/customization/theming/theming.md
index 72a901f8c078b0..9e04ed98e4f1b1 100644
--- a/docs/src/pages/customization/theming/theming.md
+++ b/docs/src/pages/customization/theming/theming.md
@@ -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
diff --git a/docs/src/pages/guides/localization/Locales.js b/docs/src/pages/guides/localization/Locales.js
new file mode 100644
index 00000000000000..331435fb25a293
--- /dev/null
+++ b/docs/src/pages/guides/localization/Locales.js
@@ -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 (
+
+
+ {}}
+ />
+ (
+
+ )}
+ />
+
+
+
+ );
+}
diff --git a/docs/src/pages/guides/localization/Locales.tsx b/docs/src/pages/guides/localization/Locales.tsx
new file mode 100644
index 00000000000000..331435fb25a293
--- /dev/null
+++ b/docs/src/pages/guides/localization/Locales.tsx
@@ -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 (
+
+
+ {}}
+ />
+ (
+
+ )}
+ />
+
+
+
+ );
+}
diff --git a/docs/src/pages/guides/localization/localization.md b/docs/src/pages/guides/localization/localization.md
new file mode 100644
index 00000000000000..b1bddbb8f9e2d6
--- /dev/null
+++ b/docs/src/pages/guides/localization/localization.md
@@ -0,0 +1,51 @@
+# Localization
+
+Localization (also referred to as "l10n") is the process of adapting a product or content to a specific locale or market.
+
+The default locale of Material-UI is English (United States). If you want to use other locales, follow the instructions below.
+
+## Locale text
+
+Use the theme to configure the locale text globally:
+
+```jsx
+import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles';
+import { zhCN } from '@material-ui/core/locale';
+
+const theme = createMuiTheme({
+ palette: {
+ primary: { main: '#1976d2' },
+ },
+}, zhCN);
+
+
+
+
+```
+
+### Supported locales
+
+| Locale | BCP 47 language tag | Import name
+|:-------|:---------|:---------|
+| Chinese (Simplified) | zh-CN | `zhCN` |
+| English (United States) | en-US | `enUS` |
+| French | fr-FR | `frFR` |
+| German | de-DE | `deDE` |
+| Japanese | ja-JP | `jaJP` |
+| Portuguese (Brazil) | pt-BR | `ptBR` |
+| Persian | fa-IR | `faIR` |
+| Russian | ru-RU | `ruRU` |
+| Spanish | es-ES | `esES` |
+
+You can [find the source](https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/locale/index.js) in the GitHub repository.
+
+To create your own translation, or to customise the English text, copy this file to your project, make any changes needed and import the locale from there. (Please do consider contributing new translations back to Material-UI by opening a pull request.)
+
+### Example
+
+{{"demo": "pages/guides/localization/Locales.js", "defaultCodeOpen": false}}
+
+## RTL Support
+
+Right-to-left languages such as Arabic or Hebrew are supported.
+Follow [this guide](/guides/right-to-left/) to use them.
diff --git a/docs/translations/translations.json b/docs/translations/translations.json
index 28d9b53a0b05fa..98c89eb0862f47 100644
--- a/docs/translations/translations.json
+++ b/docs/translations/translations.json
@@ -200,6 +200,7 @@
"/guides/testing": "Testing",
"/guides/flow": "Flow",
"/guides/right-to-left": "Right-to-left",
+ "/guides/localization": "Localization",
"/discover-more": "Discover More",
"/discover-more/showcase": "Showcase",
"/discover-more/related-projects": "Related Projects",
diff --git a/packages/material-ui-lab/src/Autocomplete/Autocomplete.d.ts b/packages/material-ui-lab/src/Autocomplete/Autocomplete.d.ts
index d9d07a7a96dcee..522553ba8ac737 100644
--- a/packages/material-ui-lab/src/Autocomplete/Autocomplete.d.ts
+++ b/packages/material-ui-lab/src/Autocomplete/Autocomplete.d.ts
@@ -46,6 +46,14 @@ export interface AutocompleteProps
* The icon to display in place of the default close icon.
*/
closeIcon?: React.ReactNode;
+ /**
+ * Override the default text for the *clear* icon button.
+ */
+ clearText?: string;
+ /**
+ * Override the default text for the *close popup* icon button.
+ */
+ closeText?: string;
/**
* If `true`, the input will be disabled.
*/
@@ -71,6 +79,10 @@ export interface AutocompleteProps
* Text to display when there are no options.
*/
noOptionsText?: React.ReactNode;
+ /**
+ * Override the default text for the *open popup* icon button.
+ */
+ openText?: string;
/**
* The component used to render the body of the popup.
*/
diff --git a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
index 3b1fe036856910..8073709bdc0c00 100644
--- a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
+++ b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
@@ -164,7 +164,9 @@ const Autocomplete = React.forwardRef(function Autocomplete(props, ref) {
classes,
className,
clearOnEscape = false,
+ clearText = 'Clear',
closeIcon = ,
+ closeText = 'Close',
debug = false,
defaultValue,
disableClearable = false,
@@ -192,6 +194,7 @@ const Autocomplete = React.forwardRef(function Autocomplete(props, ref) {
onInputChange,
onOpen,
open,
+ openText = 'Open',
options = [],
PaperComponent = Paper,
PopperComponent: PopperComponentProp = Popper,
@@ -303,8 +306,8 @@ const Autocomplete = React.forwardRef(function Autocomplete(props, ref) {
{disableClearable || disabled ? null : (
', () => {
// TODO: computeAccessibleName
expect(buttons[0]).to.have.attribute('title', 'Clear');
// TODO: computeAccessibleName
- expect(buttons[1]).to.have.attribute('title', 'Open popup');
+ expect(buttons[1]).to.have.attribute('title', 'Open');
buttons.forEach(button => {
expect(button, 'button is not in tab order').to.have.property('tabIndex', -1);
});
@@ -164,7 +164,7 @@ describe('', () => {
// TODO: computeAccessibleName
expect(buttons[0]).to.have.attribute('title', 'Clear');
// TODO: computeAccessibleName
- expect(buttons[1]).to.have.attribute('title', 'Close popup');
+ expect(buttons[1]).to.have.attribute('title', 'Close');
buttons.forEach(button => {
expect(button, 'button is not in tab order').to.have.property('tabIndex', -1);
});
@@ -452,7 +452,7 @@ describe('', () => {
renderInput={params => }
/>,
);
- expect(queryByTitle('Open popup').disabled).to.be.true;
+ expect(queryByTitle('Open').disabled).to.be.true;
});
it('should not render the clear button', () => {
diff --git a/packages/material-ui/src/TablePagination/TablePagination.js b/packages/material-ui/src/TablePagination/TablePagination.js
index 8a9cee2a08af04..cb259930378d1b 100644
--- a/packages/material-ui/src/TablePagination/TablePagination.js
+++ b/packages/material-ui/src/TablePagination/TablePagination.js
@@ -77,6 +77,7 @@ const TablePagination = React.forwardRef(function TablePagination(props, ref) {
const {
ActionsComponent = TablePaginationActions,
backIconButtonProps,
+ backIconButtonText = 'Previous page',
classes,
className,
colSpan: colSpanProp,
@@ -85,6 +86,7 @@ const TablePagination = React.forwardRef(function TablePagination(props, ref) {
labelDisplayedRows = defaultLabelDisplayedRows,
labelRowsPerPage = 'Rows per page:',
nextIconButtonProps,
+ nextIconButtonText = 'Next page',
onChangePage,
onChangeRowsPerPage,
page,
@@ -143,9 +145,17 @@ const TablePagination = React.forwardRef(function TablePagination(props, ref) {
`${from}-${to === -1 ? count : to} von ${count}`,
+ nextIconButtonText: 'Nächste Seite',
+ },
+ MuiRating: {
+ getLabelText: value => `${value} ${value !== 1 ? 'Sterne' : 'Star'}`,
+ },
+ MuiAutocomplete: {
+ clearText: 'Leeren',
+ closeText: 'Schließen',
+ loadingText: 'Wird geladen…',
+ noOptionsText: 'Keine Optionen',
+ openText: 'Öffnen',
+ },
+ },
+};
+
+// default
+export const enUS = {};
+
+/**
+ props: {
+ MuiTablePagination: {
+ backIconButtonText: 'Previous page',
+ labelRowsPerPage: 'Rows per page:',
+ labelDisplayedRows: ({ from, to, count }) => `${from}-${to === -1 ? count : to} of ${count}`,
+ nextIconButtonText: 'Next page',
+ },
+ MuiRating: {
+ getLabelText: value => `${value} Star${value !== 1 ? 's' : ''}`,
+ },
+ MuiAutocomplete: {
+ clearText: 'Clear',
+ closeText: 'Close',
+ loadingText: 'Loading…',
+ noOptionsText: 'No options',
+ openText: 'Open',
+ },
+ },
+*/
+
+export const esES = {
+ props: {
+ MuiTablePagination: {
+ backIconButtonText: 'Página anterior',
+ labelRowsPerPage: 'Filas por página:',
+ labelDisplayedRows: ({ from, to, count }) => `${from}-${to === -1 ? count : to} de ${count}`,
+ nextIconButtonText: 'Siguiente página',
+ },
+ MuiRating: {
+ getLabelText: value => `${value} Estrella${value !== 1 ? 's' : ''}`,
+ },
+ MuiAutocomplete: {
+ clearText: 'Limpiar',
+ closeText: 'Cerrar',
+ loadingText: 'Cargando…',
+ noOptionsText: 'Sin opciones',
+ openText: 'Abierto',
+ },
+ },
+};
+
+export const frFR = {
+ props: {
+ MuiTablePagination: {
+ backIconButtonText: 'Page précédente',
+ labelRowsPerPage: 'Lignes par page :',
+ labelDisplayedRows: ({ from, to, count }) => `${from}-${to === -1 ? count : to} sur ${count}`,
+ nextIconButtonText: 'Page suivante',
+ },
+ MuiRating: {
+ getLabelText: value => `${value} Etoile${value !== 1 ? 's' : ''}`,
+ },
+ MuiAutocomplete: {
+ clearText: 'Vider',
+ closeText: 'Fermer',
+ loadingText: 'Chargement…',
+ noOptionsText: 'Pas de résultats',
+ openText: 'Ouvrir',
+ },
+ },
+};
+
+export const jaJP = {
+ props: {
+ MuiTablePagination: {
+ backIconButtonText: '前のページ',
+ labelRowsPerPage: 'ページごとの行:',
+ labelDisplayedRows: ({ from, to, count }) => `${from}-${to === -1 ? count : to} of ${count}`,
+ nextIconButtonText: '次のページ',
+ },
+ MuiRating: {
+ getLabelText: value => `${value} ${value !== 1 ? '出演者' : '星'}`,
+ },
+ MuiAutocomplete: {
+ clearText: 'クリア',
+ closeText: '閉じる',
+ loadingText: '積み込み…',
+ noOptionsText: '結果がありません',
+ openText: '開いた',
+ },
+ },
+};
+
+export const ptBR = {
+ props: {
+ MuiTablePagination: {
+ backIconButtonText: 'Página anterior',
+ labelRowsPerPage: 'Linhas por página:',
+ labelDisplayedRows: ({ from, to, count }) => `${from}-${to === -1 ? count : to} de ${count}`,
+ nextIconButtonText: 'Próxima página',
+ },
+ MuiRating: {
+ getLabelText: value => `${value} Estrela${value !== 1 ? 's' : ''}`,
+ },
+ MuiAutocomplete: {
+ clearText: 'Limpar',
+ closeText: 'Fechar',
+ loadingText: 'Carregando…',
+ noOptionsText: 'Sem opções',
+ openText: 'Abrir',
+ },
+ },
+};
+
+export const ruRU = {
+ props: {
+ MuiTablePagination: {
+ backIconButtonText: 'Предыдущая страница',
+ labelRowsPerPage: 'Строк на страницу:',
+ labelDisplayedRows: ({ from, to, count }) => `${from}-${to === -1 ? count : to} of ${count}`,
+ nextIconButtonText: 'Следующая страница',
+ },
+ MuiRating: {
+ getLabelText: value => `${value} ${value !== 1 ? 'Звезды' : 'звезда'}`,
+ },
+ MuiAutocomplete: {
+ clearText: 'чистый',
+ closeText: 'близко',
+ loadingText: 'загрузка…',
+ noOptionsText: 'Нет вариантов',
+ openText: 'открыто',
+ },
+ },
+};
+
+export const zhCN = {
+ props: {
+ MuiTablePagination: {
+ backIconButtonText: '上一页',
+ labelDisplayedRows: ({ from, to, count }) => `${from}-${to === -1 ? count : to} 的 ${count}`,
+ labelRowsPerPage: '每页行数:',
+ nextIconButtonText: '下一页',
+ },
+ MuiRating: {
+ getLabelText: value => `${value} 星${value !== 1 ? '星' : ''}`,
+ },
+ MuiAutocomplete: {
+ clearText: '明确',
+ closeText: '关',
+ loadingText: '载入中…',
+ noOptionsText: '没有选择',
+ openText: '打开',
+ },
+ },
+};
+
+export const faIR = {
+ props: {
+ MuiTablePagination: {
+ backIconButtonText: 'صفحهٔ قبل',
+ labelDisplayedRows: ({ from, to, count }) => `${from}-${to === -1 ? count : to} از ${count}`,
+ labelRowsPerPage: 'تعداد سطرهای هر صفحه:',
+ nextIconButtonText: 'صفحهٔ بعد',
+ },
+ MuiRating: {
+ getLabelText: value => `${value} ستاره`,
+ },
+ MuiAutocomplete: {
+ clearText: 'پاککردن',
+ closeText: 'بستن',
+ loadingText: 'در حال بارگذاری…',
+ noOptionsText: 'بینتیجه',
+ openText: 'بازکردن',
+ },
+ },
+};
diff --git a/packages/material-ui/src/styles/createMuiTheme.d.ts b/packages/material-ui/src/styles/createMuiTheme.d.ts
index 0f0c49d6ffb151..1a7a0b781733b9 100644
--- a/packages/material-ui/src/styles/createMuiTheme.d.ts
+++ b/packages/material-ui/src/styles/createMuiTheme.d.ts
@@ -42,4 +42,4 @@ export interface Theme {
zIndex: ZIndex;
}
-export default function createMuiTheme(options?: ThemeOptions): Theme;
+export default function createMuiTheme(options?: ThemeOptions, ...args: object[]): Theme;
diff --git a/packages/material-ui/src/styles/createMuiTheme.js b/packages/material-ui/src/styles/createMuiTheme.js
index 495a8dd9d970db..24a70cdb0a804d 100644
--- a/packages/material-ui/src/styles/createMuiTheme.js
+++ b/packages/material-ui/src/styles/createMuiTheme.js
@@ -9,12 +9,11 @@ import createSpacing from './createSpacing';
import transitions from './transitions';
import zIndex from './zIndex';
-function createMuiTheme(options = {}) {
+function createMuiTheme(options = {}, ...args) {
const {
breakpoints: breakpointsInput = {},
mixins: mixinsInput = {},
palette: paletteInput = {},
- shadows: shadowsInput,
spacing: spacingInput,
typography: typographyInput = {},
...other
@@ -24,25 +23,25 @@ function createMuiTheme(options = {}) {
const breakpoints = createBreakpoints(breakpointsInput);
const spacing = createSpacing(spacingInput);
- const muiTheme = {
- breakpoints,
- direction: 'ltr',
- mixins: createMixins(breakpoints, spacing, mixinsInput),
- overrides: {}, // Inject custom styles
- palette,
- props: {}, // Inject custom props
- shadows: shadowsInput || shadows,
- typography: createTypography(palette, typographyInput),
- spacing,
- ...deepmerge(
- {
- shape,
- transitions,
- zIndex,
- },
- other,
- ),
- };
+ let muiTheme = deepmerge(
+ {
+ breakpoints,
+ direction: 'ltr',
+ mixins: createMixins(breakpoints, spacing, mixinsInput),
+ overrides: {}, // Inject custom styles
+ palette,
+ props: {}, // Provide default props
+ shadows,
+ typography: createTypography(palette, typographyInput),
+ spacing,
+ shape,
+ transitions,
+ zIndex,
+ },
+ other,
+ );
+
+ muiTheme = args.reduce((acc, argument) => deepmerge(acc, argument), muiTheme);
if (process.env.NODE_ENV !== 'production') {
const pseudoClasses = [
diff --git a/packages/material-ui/src/styles/createMuiTheme.test.js b/packages/material-ui/src/styles/createMuiTheme.test.js
index 143d0128ba3e74..ffd12ec0b38d81 100644
--- a/packages/material-ui/src/styles/createMuiTheme.test.js
+++ b/packages/material-ui/src/styles/createMuiTheme.test.js
@@ -116,4 +116,9 @@ describe('createMuiTheme', () => {
);
});
});
+
+ it('deep merges multiple arguments', () => {
+ const muiTheme = createMuiTheme({}, { foo: 'bar' });
+ assert.strictEqual(muiTheme.foo, 'bar');
+ });
});