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);

Вы можете использовать его в другом файле:

  1. импортировать новый компонент
  2. используйте его с идентификатором строки локали в качестве параметра
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));
Другие вопросы по тегам