React-Intl Как использовать FormattedMessage во входном заполнителе
Я не уверен, как получить значения от
<FormattedMessage {...messages.placeholderIntlText} />
в формат заполнителя, как ввод:
<input placeholder={<FormattedMessage {...messages.placeholderIntlText} />} />
как это возвратило бы [Объектный объект] в фактическом заполнителе. Есть ли способ получить актуальное правильное значение?
12 ответов
<Formatted... />
Реагировать компоненты в react-intl
предназначены для использования в сценариях рендеринга и не предназначены для использования в заполнителях, альтернативном тексте и т. д. Они отображают HTML, а не простой текст, что бесполезно в вашем сценарии.
Вместо, react-intl
предоставляет API более низкого уровня именно по этой же причине. Компоненты рендеринга сами используют этот API под капотами для форматирования значений в HTML. Ваш сценарий, вероятно, требует от вас использовать нижний уровень formatMessage(...)
API.
Вы должны ввести intl
объект в ваш компонент с помощью injectIntl
HOC, а затем просто отформатировать сообщение через API.
Пример:
import React from 'react';
import { injectIntl, intlShape } from 'react-intl';
const ChildComponent = ({ intl }) => {
const placeholder = intl.formatMessage({id: 'messageId'});
return(
<input placeholder={placeholder} />
);
}
ChildComponent.propTypes = {
intl: intlShape.isRequired
}
export default injectIntl(ChildComponent);
Обратите внимание, что здесь я использую некоторые функции ES6, поэтому адаптируйтесь в соответствии с вашими настройками.
- Ты можешь использовать
intl
опора изinjectIntl
Hoc - Вы также можете предоставить функцию в качестве дочернего компонента:
<FormattedMessage {...messages.placeholderIntlText}>
{(msg) => (<input placeholder={msg} />)}
</FormattedMessage>
Это июль 2019 года, и бета-версия react -intl 3 поставляется с хуком useIntl, чтобы упростить такие переводы:
import React from 'react';
import {useIntl, FormattedDate} from 'react-intl';
const FunctionComponent: React.FC<{date: number | Date}> = ({date}) => {
const intl = useIntl();
return (
<span title={intl.formatDate(date)}>
<FormattedDate value={date} />
</span>
);
};
export default FunctionComponent;
А затем вы можете создать собственные хуки для использования методов, предоставляемых API:
import { useIntl } from 'react-intl'
export function useFormatMessage(messageId) {
return useIntl().formatMessage({ id: messageId })
}
Для ввода заполнителя для более подробной информации
<FormattedMessage id="yourid" defaultMessage="search">
{placeholder=>
<Input placeholder={placeholder}/>
}
</FormattedMessage>
Начиная с версии React>= 16.8, вы можете использовать хук useIntl:
import React from 'react';
import { IntlProvider, useIntl } from 'react-intl';
const FunctionComponent = () => {
const intl = useIntl();
const lang = "en";
const messages = {
en: {
'placeholderMessageId': 'placeholder in english',
},
fr: {
'placeholderMessageId': 'placeholder en fançais',
}
}
return (
<IntlProvider locale = {lang} messages = { messages[lang] } >
<input placeholder = { intl.formatMessage({ id: 'placeholderMessageId' })}/>
</IntlProvider >
);
};
export default FunctionComponent;
Исходя из вики реагирования, реализация поля ввода с переводимым заполнителем будет выглядеть следующим образом:
import React from 'react';
import { injectIntl, intlShape, defineMessages } from 'react-intl';
const messages = defineMessages({
placeholder: {
id: 'myPlaceholderText',
defaultMessage: '{text} and static text',
},
});
const ComponentWithInput = ({ intl, placeholderText }) => {
return (
<input
placeholder={ intl.formatMessage(messages.placeholder, { text: placeholderText }) }
/>
);
};
ComponentWithInput.propTypes = {
intl: intlShape.isRequired
};
export default injectIntl(ComponentWithInput);
и использование этого:
import ComponentWithInput from './component-with-input';
...
render() {
<ComponentWithInput placeholderText="foo" />
}
...
id: 'myPlaceholderText',
часть необходима, чтобы позволить babel-plugin-реагировать-intl собирать сообщения для перевода.
Я хотел бы предложить это решение:
import { useIntl } from "react-intl";
export default function MyComponent() {
const intl = useIntl();
return (
<input placeholder={intl.formatMessage({ id: "messageId" })} />
);
}
Вы пытаетесь отобразить компонент React с именем FormattedMessage в тег-заполнитель, который ожидает строку.
Вместо этого вы должны просто создать функцию с именем FormattedMessage, которая возвращает строку в заполнитель.
function FormattedMessage(props) {
...
}
<input placeholder=`{$(FormattedMessage({...messages.placeholderIntlText})}` />
Учтите эту возможность.
Самое простое решение
<IntlMessages id="category.name">
{text => (
<Input placeholder={text} />
)}
</IntlMessages>
ИЛИ
Начиная с ответа @gazdagerg, я адаптировал его код, чтобы:
- наличие нового компонента, который является оболочкой над входом
- получает идентификатор строки из locale conf
- на основе идентификатора, он возвращает строку в соответствии с глобальной настройкой локали
- обработка ситуации, когда идентификатор строки не установлен (это привело к сбою исключения и страницы)
import React from 'react';
import { injectIntl, intlShape, defineMessages } from 'react-intl';
const InputWithPlaceholder = ({ intl, placeholder }) => {
const messages = defineMessages({
placeholder: {
id: placeholder,
defaultMessage: '',
},
});
if(messages.placeholder.id) {
return (
<input placeholder={ intl.formatMessage(messages.placeholder) } />
);
} else {
return (
<input/>
);
}
};
InputWithPlaceholder.propTypes = {
intl: intlShape.isRequired
};
export default injectIntl(InputWithPlaceholder);
Вы можете использовать его в другом файле:
- импортировать новый компонент
- используйте его с идентификатором строки локали в качестве параметра
import InputWithIntlPlaceholder from 'your/path/to/component/InputWithIntlPlaceholder';
... more code here ...
<InputWithIntlPlaceholder placeholder="your.locale.string.id" />
В моем случае у меня было все приложение в одном файле, поэтому с помощью export
не сработает. Этот использует нормальную структуру классов, так что вы можете использовать состояние и другие функции React, если это необходимо.
class nameInputOrig extends React.Component {
render () {
const {formatMessage} = this.props.intl;
return (
<input type="text" placeholder={formatMessage({id:"placeholderIntlText"})} />
);
}
}
const nameInput = injectIntl(nameInputOrig);
Применить, используя созданную константу:
class App extends React.Component {
render () {
<nameInput />
}
}
Как это:
import React, {PropTypes} from 'react';
import { injectIntl, FormattedMessage } from 'react-intl';
/**
* {
* "hello": "Hello",
* "world": "World"
* }
*/
// pure function
const PureFunciton = injectIntl(({ intl }) => {
return (
<div>
<p>{intl.formatMessage({ id: 'hello' })}</p>
<p><FormattedMessage id="world" /></p>
</div>
)
});
// class Component
class componentName extends Component {
handleStr = () => {
// return 'Hello';
const { intl } = this.props;
return intl.formatMessage({ id: 'hello' })
}
render() {
return (
<div>
<p>{this.handleStr()}</p>
<p><FormattedMessage id="world" /></p>
</div>
);
}
}
export default injectIntl(connect(componentName));