如何使用React-Intl呈现格式化消息列表

时间:2018-10-10 16:56:10

标签: javascript reactjs react-intl

我有一个navigation,其中包含标准项目,例如:联系方式,服务,价格等...我将其呈现为:

const menuItemList = menuItems.map((item, index) => {
    return (
        <li key={index}>
            <NavLink to={item.url}>{item.title}</NavLink>
        </li>
    );
});

工作正常。但是现在我需要翻译此导航,为此我使用了react-intl库。根据{{​​1}} doc,我必须像这样使用react-intl

FormattedMessage

有效。但是如何将其用于列表呈现?我认为它可以解决此问题,但是不行。

<p>
   <FormattedMessage id="mainText"/>
</p> 

伙计们,请帮忙。如何使用const menuItemsList = menuItems.map((item, index) => { return ( <li key={index}> <NavLink to={item.url}> <FormattedMessage id="mainText" values={item.title}/> </NavLink> </li> ); }); 中的ReactFormattedMessage中的项目呈现列表?

3 个答案:

答案 0 :(得分:0)

您需要将消息传递给intl。例如:

{
    profile: 'Profile',
    settings: 'Settings'
}

我想你也有

const menuItems = [
    {
        url: '/profile',
        title: 'profile'
    },
    {
        url: '/settings',
        title: 'settings'
    }
] 

因此您可以像这样使用它

const menuItemsList = menuItems.map((item, index) => {
    return (
        <li key={index}>
            <NavLink to={item.url}>
                <FormattedMessage id={item.title} />
            </NavLink>
        </li>
    );
});

答案 1 :(得分:0)

您可以使用defineMessages

const menuItemsList = menuItems.map((item, index) => {
  return (
    <li key={index}>
      <NavLink to={item.url}>
        <FormattedMessage {...MSG[`item_${index}`]} />
      </NavLink>
    </li>
  );
});

const MSG = defineMessages({
  item_0: {
    id: 'items.service',
    defaultMessage: 'Service'
  },
  item_1: {
    id: 'items.contact',
    defaultMessage: 'Contact'
  }
})

答案 2 :(得分:0)

我最近遇到了同样的问题。 React Intl 不允许将数组传递给 <FormattedMessage />,因此假设您有大量翻译项目,例如这个英文消息对象:

{
    "page.title": "Test Page",
    "page.menuItems": ["First english Item", "second english Item", ... , "100th english item"]
}

您需要一个解决方法。这个想法是我们希望通过嵌套索引而不是全局 id 访问这些项目。

现在我找到了两种解决方案来实现这一目标:

  1. 通过索引直接访问 intl 消息中的嵌套消息(hacky & fast):
import React from "react"
import {useIntl} from 'react-intl'
import NavLink from 'somewhere'

const Menu = ({menuItems}) => {
    const intl = useIntl();
    const menuItemsIntl = intl.messages["page.menuItems"]; 
    return (<div>
        {menuItems.map((item, index) => 
        <li key={index}>
            <NavLink to={item.url}>
                {menuItemsIntl[index]}
            </NavLink>
        </li>}
   </div>);
});

export default Menu;

这有一个缺点,即您没有 React Intl 的后备功能,以防您没有可用的翻译。您需要围绕 FormatMessage 编写自定义 menuItemsIntl[index] 组件来处理丢失的键。

  1. 在将消息对象注入提供程序之前将其展平,然后通过计算出的唯一密钥(安全且健壮)访问它:

我们需要消息对象看起来像这样:

{
    "page.title": "Test Page",
    "page.menuItems.1": "First english Item", 
    "page.menuItems.2": "Second english Item", 
    ...
    "page.menuItems.100": "100th english item"
}

为了得到它,我们需要扁平化原始消息对象,例如使用以下变异函数:

import translations from "./translations.json";

const Root = ()=> {
  const [lan, setLan]= useState("en");
  const messages = translations[lan]
  const flattenMessages = (obj, parKey = "") => {
    Object.keys(obj).forEach((key) => {
      const currKey = parKey + (parKey.length > 0 ? "." : "") + key;
      if (Array.isArray(obj[key]) || typeof obj[key] === 'object') {
        flattenMessages (obj[key], currKey)
      } else if (typeof obj[key] === "string") {
        messages[currKey] = obj[key]
      }
    })
  }
  flattenMessages({...messages})

  return <IntlProvider 
    key={lan}
    messages={messages}
    locale={lan} 
    defaultLocale="en"
    >
       <App />
  </IntlProvider>
};

然后您就可以像习惯一样使用带有 id 的 FormattedMessage。您只需要根据 jsx 中的迭代器计算 id 字符串。

const Menu = ({menuItems}) => {
    return (<div>
        {menuItems.map((item, index) => 
        <li key={index}>
            <NavLink to={item.url}>
                <FormattedMessage id={`page.menuItems.${index}.title`} />
            </NavLink>
        </li>}
   </div>);
});

我编写了第一个解决方案,以防有人不知道您可以直接访问消息对象。但是,对于大多数情况,我会推荐第二种解决方案。