diff --git a/components/date-picker/PickerMixin.jsx b/components/date-picker/PickerMixin.jsx
index 837fba5e01..f936dabe69 100644
--- a/components/date-picker/PickerMixin.jsx
+++ b/components/date-picker/PickerMixin.jsx
@@ -1,14 +1,23 @@
+import React from 'react';
import objectAssign from 'object-assign';
import defaultLocale from './locale/zh_CN';
import DateTimeFormat from 'gregorian-calendar-format';
import GregorianCalendar from 'gregorian-calendar';
export default {
+ contextTypes: {
+ antLocale: React.PropTypes.object,
+ },
+
getLocale() {
+ let locale = defaultLocale;
+ if (this.context.antLocale && this.context.antLocale.DatePicker) {
+ locale = this.context.antLocale.DatePicker;
+ }
// 统一合并为完整的 Locale
- let locale = objectAssign({}, defaultLocale, this.props.locale);
- locale.lang = objectAssign({}, defaultLocale.lang, this.props.locale.lang);
- return locale;
+ const result = objectAssign({}, locale, this.props.locale);
+ result.lang = objectAssign({}, locale.lang, this.props.locale.lang);
+ return result;
},
getFormatter() {
diff --git a/components/locale-provider/demo/all.md b/components/locale-provider/demo/all.md
new file mode 100644
index 0000000000..6a5e5c6233
--- /dev/null
+++ b/components/locale-provider/demo/all.md
@@ -0,0 +1,131 @@
+# 所有组件
+
+- order: 2
+
+此处列出 Ant Design 中需要国际化支持的组件,你可以在演示里切换语言。
+
+---
+
+````jsx
+import { LocaleProvider, Pagination, DatePicker, TimePicker,
+ Popconfirm, Table, Modal, Button, Select, Transfer } from 'antd';
+import enUS from 'antd/lib/locale-provider/en_US';
+const Option = Select.Option;
+
+const columns = [{
+ title: 'Name',
+ dataIndex: 'name',
+ filters: [{
+ text: 'filter1',
+ value: 'filter1',
+ }],
+}, {
+ title: 'Age',
+ dataIndex: 'age',
+}];
+
+const Page = React.createClass({
+ getInitialState() {
+ return {
+ visible: false,
+ };
+ },
+ showModal() {
+ this.setState({ visible: true });
+ },
+ hideModal() {
+ this.setState({ visible: false });
+ },
+ render() {
+ const info = () => {
+ Modal.info({
+ title: 'some info',
+ content: 'some info',
+ });
+ };
+ const confirm = () => {
+ Modal.confirm({
+ title: 'some info',
+ content: 'some info',
+ });
+ };
+ return (
+
+
+
+
+ item.title} />
+
+
+
+ Locale Modal
+
+
+ );
+ }
+});
+
+const App = React.createClass({
+ getInitialState() {
+ return {
+ locale: enUS,
+ };
+ },
+ changeLocale(locale) {
+ this.setState({ locale });
+ },
+ render() {
+ return (
+
+
+ Change locale of components:
+
+
+
+
+ );
+ }
+});
+
+ReactDOM.render(, mountNode);
+````
+
+````css
+.locale-components {
+ border-top: 1px solid #d9d9d9;
+ padding-top: 16px;
+}
+
+.example {
+ margin: 16px 0;
+}
+
+.example > * {
+ margin-right: 8px;
+}
+
+.change-locale {
+ margin-bottom: 16px;
+}
+````
diff --git a/components/locale-provider/demo/basic.md b/components/locale-provider/demo/basic.md
new file mode 100644
index 0000000000..8137c42259
--- /dev/null
+++ b/components/locale-provider/demo/basic.md
@@ -0,0 +1,28 @@
+# 国际化
+
+- order: 1
+
+用 `LocaleProvider` 包裹你的应用,并引用对应的语言包。
+
+---
+
+````jsx
+import { Pagination, LocaleProvider } from 'antd';
+import enUS from 'antd/lib/locale-provider/en_US';
+
+const App = React.createClass({
+ render() {
+ return (
+
+ );
+ }
+});
+
+ReactDOM.render(
+
+
+
+, mountNode);
+````
diff --git a/components/locale-provider/en_US.js b/components/locale-provider/en_US.js
new file mode 100644
index 0000000000..9e5b243e76
--- /dev/null
+++ b/components/locale-provider/en_US.js
@@ -0,0 +1,26 @@
+module.exports = {
+ Pagination: require('rc-pagination/lib/locale/en_US'),
+ DatePicker: require('../date-picker/locale/en_US'),
+ TimePicker: require('../time-picker/locale/en_US'),
+ Table: {
+ filterTitle: 'Filter Menu',
+ filterConfirm: 'OK',
+ filterReset: 'Reset',
+ emptyText: 'No Data',
+ },
+ Modal: {
+ okText: 'OK',
+ cancelText: 'Cancel',
+ justOkText: 'OK',
+ },
+ Popconfirm: {
+ okText: 'OK',
+ cancelText: 'Cancel',
+ },
+ Transfer: {
+ notFoundContent: 'Not Found',
+ searchPlaceholder: 'Search here',
+ itemUnit: 'item',
+ itemsUnit: 'items',
+ },
+};
diff --git a/components/locale-provider/index.jsx b/components/locale-provider/index.jsx
new file mode 100644
index 0000000000..9588eb5eec
--- /dev/null
+++ b/components/locale-provider/index.jsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import { changeConfirmLocale } from '../modal/confirm';
+
+export default class LocaleProvider extends React.Component {
+ getChildContext() {
+ return {
+ antLocale: this.props.locale,
+ };
+ }
+ componentDidMount() {
+ this.componentDidUpdate();
+ }
+ componentDidUpdate() {
+ const { locale } = this.props;
+ changeConfirmLocale(locale && locale.Modal);
+ }
+ componentWillUnMount() {
+ changeConfirmLocale();
+ }
+ render() {
+ return React.Children.only(this.props.children);
+ }
+}
+
+LocaleProvider.childContextTypes = {
+ antLocale: React.PropTypes.object,
+};
+
+LocaleProvider.propTypes = {
+ locale: React.PropTypes.object,
+};
diff --git a/components/locale-provider/index.md b/components/locale-provider/index.md
new file mode 100644
index 0000000000..dfe6ee1c59
--- /dev/null
+++ b/components/locale-provider/index.md
@@ -0,0 +1,36 @@
+# LocaleProvider
+
+- category: Components
+- chinese: 国际化
+- cols: 1
+
+---
+
+为组件内建文案提供统一的国际化支持。
+
+## 使用
+
+LocaleProvider 使用 React 的 [context](https://facebook.github.io/react/docs/context.html) 特性,只需在应用外围包裹一次即可全局生效。
+
+
+```jsx
+import enUS from 'antd/lib/locale-provider/en_US';
+
+...
+
+return ;
+```
+
+### Add a language
+
+We supply an English locale package by now. Other language users can custumize your locale package as [en_US](https://github.com/ant-design/ant-design/blob/26b1f37392a278285aec6c573b99c6feea09e218/components/locale-provider/en_US.js) and ask a pull request to us.
+
+### 其他国际化需求
+
+本模块仅用于组件的内建文案,若有业务文案的国际化需求,建议使用 [react-intl](https://github.com/yahoo/react-intl),可参考示例:[Intl demo 1](http://github.com/ant-design/intl-example) 和 [Intl demo 2](http://yiminghe.me/learning-react/examples/react-intl.html?locale=en-US)。
+
+## API
+
+| 参数 | 说明 | 类型 | 默认值 |
+|--------|----------------|------------------|--------------|
+| locale | 语言包配置,语言包可到 `antd/lib/locale-provider/` 目录下寻找 | Object | - |
diff --git a/components/modal/Modal.jsx b/components/modal/Modal.jsx
index 7bf8f2a311..bd2274306b 100644
--- a/components/modal/Modal.jsx
+++ b/components/modal/Modal.jsx
@@ -14,8 +14,6 @@ let AntModal = React.createClass({
prefixCls: 'ant-modal',
onOk: noop,
onCancel: noop,
- okText: '确定',
- cancelText: '取消',
width: 520,
transitionName: 'zoom',
maskAnimation: 'fade',
@@ -24,6 +22,10 @@ let AntModal = React.createClass({
};
},
+ contextTypes: {
+ antLocale: React.PropTypes.object,
+ },
+
handleCancel(e) {
this.props.onCancel(e);
},
@@ -52,19 +54,26 @@ let AntModal = React.createClass({
render() {
let props = this.props;
+
+ let { okText, cancelText } = props;
+ if (this.context.antLocale && this.context.antLocale.Modal) {
+ okText = okText || this.context.antLocale.Modal.okText;
+ cancelText = cancelText || this.context.antLocale.Modal.cancelText;
+ }
+
let defaultFooter = [
,
];
let footer = props.footer || defaultFooter;
diff --git a/components/modal/confirm.jsx b/components/modal/confirm.jsx
index 28f95931db..10a1c2f0c4 100644
--- a/components/modal/confirm.jsx
+++ b/components/modal/confirm.jsx
@@ -5,8 +5,24 @@ import Icon from '../icon';
import Button from '../button';
import objectAssign from 'object-assign';
-export default function (config) {
- const props = objectAssign({}, config || {});
+const defaultLocale = {
+ okText: '确定',
+ cancelText: '取消',
+ justOkText: '知道了',
+};
+
+let runtimeLocale = { ...defaultLocale };
+
+export function changeConfirmLocale(newLocale) {
+ if (newLocale) {
+ objectAssign(runtimeLocale, newLocale);
+ } else {
+ runtimeLocale = { ...defaultLocale };
+ }
+}
+
+export default function confirm(config) {
+ const props = objectAssign({}, config);
let div = document.createElement('div');
document.body.appendChild(div);
@@ -22,12 +38,13 @@ export default function (config) {
props.okCancel = true;
}
- props.okText = props.okText || (props.okCancel ? '确定' : '知道了');
- props.cancelText = props.cancelText || '取消';
+ props.okText = props.okText ||
+ (props.okCancel ? runtimeLocale.okText : runtimeLocale.justOkText);
+ props.cancelText = props.cancelText || runtimeLocale.cancelText;
function close() {
d.setState({
- visible: false
+ visible: false,
});
ReactDOM.unmountComponentAtNode(div);
div.parentNode.removeChild(div);
diff --git a/components/pagination/demo/locale.md b/components/pagination/demo/locale.md
deleted file mode 100644
index d617906b86..0000000000
--- a/components/pagination/demo/locale.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# 国际化
-
-- order: 7
-
-通过 `locale` 配置时区、语言等, 默认支持 en_US, zh_CN
-
----
-
-````jsx
-import { Pagination } from 'antd';
-import enUS from 'antd/lib/pagination/locale/en_US';
-
-ReactDOM.render(
- ,
- mountNode);
-````
diff --git a/components/pagination/index.jsx b/components/pagination/index.jsx
index 1bbf3ac0cf..725d20a0a5 100644
--- a/components/pagination/index.jsx
+++ b/components/pagination/index.jsx
@@ -16,6 +16,13 @@ class AntPagination extends React.Component {
let className = this.props.className;
let selectComponentClass = Select;
+ let locale;
+ if (this.context.antLocale && this.context.antLocale.Pagination) {
+ locale = this.context.antLocale.Pagination;
+ } else {
+ locale = this.props.locale;
+ }
+
if (this.props.size === 'small') {
className += ' mini';
selectComponentClass = MiniSelect;
@@ -25,6 +32,7 @@ class AntPagination extends React.Component {
);
}
@@ -36,4 +44,8 @@ AntPagination.defaultProps = {
prefixCls: 'ant-pagination',
};
+AntPagination.contextTypes = {
+ antLocale: React.PropTypes.object,
+};
+
export default AntPagination;
diff --git a/components/popconfirm/index.jsx b/components/popconfirm/index.jsx
index 79e21f0747..887ea73d59 100644
--- a/components/popconfirm/index.jsx
+++ b/components/popconfirm/index.jsx
@@ -34,11 +34,12 @@ export default React.createClass({
overlayStyle: {},
onConfirm: noop,
onCancel: noop,
- okText: '确定',
- cancelText: '取消',
onVisibleChange() {},
};
},
+ contextTypes: {
+ antLocale: React.PropTypes.object,
+ },
componentWillReceiveProps(nextProps) {
if ('visible' in nextProps) {
this.setState({ visible: nextProps.visible });
@@ -62,7 +63,12 @@ export default React.createClass({
}
},
render() {
- const { title, okText, cancelText, placement, overlayStyle, trigger, ...restProps } = this.props;
+ const { title, placement, overlayStyle, trigger, ...restProps } = this.props;
+ let { okText, cancelText } = this.props;
+ if (this.context.antLocale && this.context.antLocale.Popconfirm) {
+ okText = okText || this.context.antLocale.Popconfirm.okText;
+ cancelText = cancelText || this.context.antLocale.Popconfirm.cancelText;
+ }
const overlay = (
@@ -71,8 +77,8 @@ export default React.createClass({
{title}
-
-
+
+
diff --git a/components/table/index.jsx b/components/table/index.jsx
index 32ffc4d205..dc82598d12 100644
--- a/components/table/index.jsx
+++ b/components/table/index.jsx
@@ -74,6 +74,10 @@ let AntTable = React.createClass({
locale: React.PropTypes.object,
},
+ contextTypes: {
+ antLocale: React.PropTypes.object,
+ },
+
getDefaultSelection() {
if (!this.props.rowSelection || !this.props.rowSelection.getCheckboxProps) {
return [];
@@ -83,6 +87,14 @@ let AntTable = React.createClass({
.map((record, rowIndex) => this.getRecordKey(record, rowIndex));
},
+ getLocale() {
+ let locale = {};
+ if (this.context.antLocale && this.context.antLocale.Table) {
+ locale = this.context.antLocale.Table;
+ }
+ return objectAssign({}, defaultLocale, locale, this.props.locale);
+ },
+
componentWillReceiveProps(nextProps) {
if (('pagination' in nextProps) && nextProps.pagination !== false) {
this.setState({
@@ -405,7 +417,7 @@ let AntTable = React.createClass({
},
renderColumnsDropdown(columns) {
- let locale = objectAssign({}, defaultLocale, this.props.locale);
+ const locale = this.getLocale();
return columns.map((originColumn, i) => {
let column = objectAssign({}, originColumn);
let key = this.getColumnKey(column, i);
@@ -563,7 +575,7 @@ let AntTable = React.createClass({
const data = this.getCurrentPageData();
let columns = this.renderRowSelection();
const expandIconAsCell = this.props.expandedRowRender && this.props.expandIconAsCell !== false;
- const locale = objectAssign({}, defaultLocale, this.props.locale);
+ const locale = this.getLocale();
const classString = classNames({
[`ant-table-${this.props.size}`]: true,
diff --git a/components/time-picker/index.jsx b/components/time-picker/index.jsx
index aecc2e727f..5240390c4d 100644
--- a/components/time-picker/index.jsx
+++ b/components/time-picker/index.jsx
@@ -27,6 +27,10 @@ const AntTimePicker = React.createClass({
};
},
+ contextTypes: {
+ antLocale: React.PropTypes.object,
+ },
+
getFormatter() {
return new DateTimeFormat(this.props.format);
},
@@ -68,14 +72,19 @@ const AntTimePicker = React.createClass({
},
getLocale() {
+ let locale = defaultLocale;
+ if (this.context.antLocale && this.context.antLocale.TimePicker) {
+ locale = this.context.antLocale.TimePicker;
+ }
// 统一合并为完整的 Locale
- return objectAssign({}, defaultLocale, this.props.locale);
+ return objectAssign({}, locale, this.props.locale);
},
render() {
+ const locale = this.getLocale();
const props = objectAssign({}, this.props);
props.placeholder = ('placeholder' in this.props)
- ? props.placeholder : this.getLocale().placeholder;
+ ? props.placeholder : locale.placeholder;
if (props.defaultValue) {
props.defaultValue = this.parseTimeFromValue(props.defaultValue);
} else {
@@ -99,7 +108,7 @@ const AntTimePicker = React.createClass({
diff --git a/components/transfer/index.jsx b/components/transfer/index.jsx
index eef2f2b9e6..f57bfaf72c 100644
--- a/components/transfer/index.jsx
+++ b/components/transfer/index.jsx
@@ -223,8 +223,6 @@ Transfer.defaultProps = {
titles: ['源列表', '目的列表'],
operations: [],
showSearch: false,
- searchPlaceholder: '请输入搜索内容',
- notFoundContent: 'Not Found',
body: noop,
footer: noop,
};
diff --git a/components/transfer/index.md b/components/transfer/index.md
index 51326c12f9..4f28a8e81e 100644
--- a/components/transfer/index.md
+++ b/components/transfer/index.md
@@ -27,6 +27,6 @@
| titles | 标题集合,顺序从左至右 | Array | ['源列表', '目的列表'] |
| operations | 操作文案集合,顺序从上至下 | Array | [] |
| showSearch | 是否显示搜索框 | Boolean | false |
-| searchPlaceholder | 搜索框的默认值 | String | 请输入搜索的内容 |
-| notFoundContent | 当列表为空时显示的内容 | React.node | 'Not Found' |
+| searchPlaceholder | 搜索框的默认值 | String | '请输入搜索内容' |
+| notFoundContent | 当列表为空时显示的内容 | React.node | '列表为空' |
| footer | 底部渲染函数 | Function(props) | | |
diff --git a/components/transfer/list.jsx b/components/transfer/list.jsx
index 0b34cc2913..e22c0f8056 100644
--- a/components/transfer/list.jsx
+++ b/components/transfer/list.jsx
@@ -69,8 +69,10 @@ class TransferList extends Component {
}
render() {
- const { prefixCls, dataSource, titleText, filter, checkedKeys, notFoundContent,
- checkStatus, body, footer, showSearch, searchPlaceholder } = this.props;
+ const { prefixCls, dataSource, titleText, filter, checkedKeys,
+ checkStatus, body, footer, showSearch } = this.props;
+
+ let { searchPlaceholder, notFoundContent } = this.props;
// Custom Layout
const footerDom = footer({ ...this.props });
@@ -95,6 +97,18 @@ class TransferList extends Component {
);
});
+ let unit = '条';
+ if (this.context.antLocale &&
+ this.context.antLocale.Transfer) {
+ unit = dataSource.length > 1
+ ? this.context.antLocale.Transfer.itemsUnit
+ : this.context.antLocale.Transfer.itemUnit;
+ searchPlaceholder = searchPlaceholder
+ || this.context.antLocale.Transfer.searchPlaceholder;
+ notFoundContent = notFoundContent
+ || this.context.antLocale.Transfer.notFoundContent;
+ }
+
return (
@@ -103,8 +117,15 @@ class TransferList extends Component {
checked: checkStatus === 'all',
checkPart: checkStatus === 'part',
checkable:
- })}{(checkedKeys.length > 0 ? `${checkedKeys.length}/` : '') + dataSource.length} 条
- {titleText}
+ })}
+
+
+ {(checkedKeys.length > 0 ? `${checkedKeys.length}/` : '') + dataSource.length} {unit}
+
+
+ {titleText}
+
+
{ bodyDom ||
@@ -112,13 +133,15 @@ class TransferList extends Component {
: null }
- {showItems.length > 0 ? showItems : {notFoundContent}
}
+ {showItems.length > 0
+ ? showItems
+ : {notFoundContent || '列表为空'}
}
}
{ footerDom ?
@@ -133,7 +156,6 @@ TransferList.defaultProps = {
dataSource: [],
titleText: '',
showSearch: false,
- searchPlaceholder: '',
handleFilter: noop,
handleSelect: noop,
handleSelectAll: noop,
@@ -158,4 +180,8 @@ TransferList.propTypes = {
footer: PropTypes.func,
};
+TransferList.contextTypes = {
+ antLocale: React.PropTypes.object,
+};
+
export default TransferList;
diff --git a/index.js b/index.js
index 8d81517e75..695ace85ac 100644
--- a/index.js
+++ b/index.js
@@ -46,6 +46,7 @@ const antd = {
Transfer: require('./components/transfer'),
Cascader: require('./components/cascader'),
Card: require('./components/card'),
+ LocaleProvider: require('./components/locale-provider'),
};
module.exports = antd;
diff --git a/scripts/demo.js b/scripts/demo.js
index 62278e0bd6..9aad398c00 100644
--- a/scripts/demo.js
+++ b/scripts/demo.js
@@ -61,6 +61,8 @@ antd.Pagination.locale = {
zh_CN: require('../components/pagination/locale/zh_CN'),
};
+antd.LocaleProvider['en_US'] = require('../components/locale-provider/en_US'),
+
InstantClickChangeFns.push(function () {
// auto complete for components
var Select = antd.Select;