I'm unsure how to get the values from
<FormattedMessage {...messages.placeholderIntlText} />
into a placeholder format like input:
<input placeholder={<FormattedMessage {...messages.placeholderIntlText} />} />
as it would return [Object object] in the actual placeholder. Is there a way to get the actual correct value?
The <Formatted... />
React components in react-intl
are meant to be used in rendering scenarios and are not meant to be used in placeholders, alternate text, etc. They render HTML, not plain text, which is not useful in your scenario.
Instead, react-intl
provides a lower level API for exactly this same reason. The rendering components themselves use this API under the hoods to format the values into HTML. Your scenario probably requires you to use the lower level formatMessage(...)
API.
You should inject the intl
object into your component by using the injectIntl
HOC and then just format the message through the API.
Example:
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);
Please note that I'm using some ES6 features here, so adapt according to your setup.
- You can use
intl
prop frominjectIntl
HoC - You can also provide function as child component:
<FormattedMessage {...messages.placeholderIntlText}>
{(msg) => (<input placeholder={msg} />)}
</FormattedMessage>
For Input placeholder for more details
<FormattedMessage id="yourid" defaultMessage="search">
{placeholder=>
<Input placeholder={placeholder}/>
}
</FormattedMessage>
Based on the react intl wiki the implementation of an input box with translatable placeholder will look like:
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);
and the useage of it:
import ComponentWithInput from './component-with-input';
...
render() {
<ComponentWithInput placeholderText="foo" />
}
...
The id: 'myPlaceholderText',
part is necessary to enable the babel-plugin-react-intl to collect the messages for translation.
You are trying to render a React component named FormattedMessage into a placeholder tag which is expecting a string.
You should instead just create a function named FormattedMessage that returns a string into the placeholder.
function FormattedMessage(props) {
...
}
<input placeholder=`{$(FormattedMessage({...messages.placeholderIntlText})}` />
It's july 2019 and react-intl 3 beta is shipped with a useIntl hook to make these kind of translations easier:
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;
And then you can make custom hooks to use the methods provided by the API:
import { useIntl } from 'react-intl'
export function useFormatMessage(messageId) {
return useIntl().formatMessage({ id: messageId })
}
In my case I had the whole app in one file, so using export
wouldn't work. This one uses the normal class structure so you can use the state and other functionality of React if needed.
class nameInputOrig extends React.Component {
render () {
const {formatMessage} = this.props.intl;
return (
<input type="text" placeholder={formatMessage({id:"placeholderIntlText"})} />
);
}
}
const nameInput = injectIntl(nameInputOrig);
Apply using the created constant:
class App extends React.Component {
render () {
<nameInput />
}
}
Starting from the @gazdagerg 's answer, I have adapted his code in order to:
- having a new component that is a wrapper over an input
- receives an ID of a string from locale conf
- based on the ID, it returns the string in respect to the global locale setting
- handling the situation when the string ID is not set (this caused exception and page to crash)
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);
You can use it in other file by:
- import the new component
- use it with the ID of the locale string as parameter
import InputWithIntlPlaceholder from 'your/path/to/component/InputWithIntlPlaceholder';
... more code here ...
<InputWithIntlPlaceholder placeholder="your.locale.string.id" />
Like this:
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));
来源:https://stackoverflow.com/questions/39630620/react-intl-how-to-use-formattedmessage-in-input-placeholder