1

I have a component that needs strings from the backend. I currently request the .po file from the server, convert it to .json and return it to my React component. I then want to be able to display those strings whilst replacing the correct values in the string, i.e.

<FormattedMessage id={dynamicId} values={dynamicVals} />

dynamicId is pulled from a separate api call, as well as dynamicVals.

My problem is that these strings are not bundled like all of my other app strings, so react-intl is unaware of them. How can I add these strings to the library client-side/async? I've attempted using defineMessages and addLocaleData, but I either am doing something incorrectly, or am not using the right api methods. Does addLocaleData provide the means to adding strings to the library? Is this possible to do?

In summary:

How can I receive

{
  notifications.friendships.nowfriends: "{name} is now your friend"
}

from the api and display it using:

<FormattedMessage id='notifications.friendships.nowfriends' values={{ name: 'StackOver Bro' }} />

Thanks for the help in advance.

jacoballenwood
  • 2,787
  • 2
  • 24
  • 39
  • Have you tried ` id={notifications.friendships.nowfriends}` – bennygenel Sep 23 '17 at 20:10
  • yes, of course. but react-intl does not have any reference to that id. I'm wondering how to add the string to the library from within the react component where i make the api call and display the strings – jacoballenwood Sep 23 '17 at 20:11
  • I didn't use the library before so I'm just guessing. Can you use [`addlocaledata`](https://github.com/yahoo/react-intl/wiki/API#addlocaledata) with the result of your API call? Or [`definemessages`](https://github.com/yahoo/react-intl/wiki/API#definemessages) – bennygenel Sep 23 '17 at 20:18
  • I’ve attempted both those things but to no avail. It’s very possible I’m doing it incorrectly though. I haven’t really been able to find any examples of what I’m trying to do. – jacoballenwood Sep 23 '17 at 20:27
  • If you haven't tried can you try `` – bennygenel Sep 23 '17 at 20:36
  • using `defaultMessage` yields this result: `[React Intl] Messages must be statically evaluate-able for extraction.` – jacoballenwood Sep 23 '17 at 20:40
  • Does it work when you type manually `defaultMessage='{name} is now your friend'` – bennygenel Sep 23 '17 at 20:44
  • Honestly i think react-intl isn't just friendly for that usecase...it is build on a flow where strings live in your app and get extracted and parsed and bundled using webpack. You might give react-i18next a try: https://github.com/i18next/react-i18next based on i18next it is build around the loading translations from server via xhr and take care of loading is done before showing your components. – jamuhl Sep 24 '17 at 13:45
  • Thanks for the comment. It guided me to abandon using React-intl for this use case! – jacoballenwood Sep 24 '17 at 21:30

1 Answers1

0

In case anyone wants to know what I ended up doing...

Since I already had the strings and the variables to interpolate with, I bypassed the localization library and just used the following function (thanks to the answers on this question, especially @user2501097 and @Bryan Rayner)

/**
 *  see: https://stackoverflow.com/questions/29182244/convert-a-string-to-a-template-string
 *
 * Produces a function which uses template strings to do simple interpolation from objects.
 *
 * Usage:
 *    var makeMeKing = generateTemplateString('${name} is now the king of {country}!');
 *
 *    console.log(makeMeKing({ name: 'Bryan', country: 'Scotland'}));
 *    // Logs 'Bryan is now the king of Scotland!'
 */
const generateTemplateString = (function () {
    const cache = {}

    function generateTemplate(template) {
        let fn = cache[template]

        if (!fn) {
            // Replace ${expressions} (etc) with ${map.expressions}.
            const sanitized = template
                .replace(/\$?\{([\s]*[^;\s\{]+[\s]*)\}/g, (_, match) => {
                    return `\$\{map.${match.trim()}\}`
                })
                // Afterwards, replace anything that's not ${map.expressions}' (etc) with a blank string.
                .replace(/(\$\{(?!map\.)[^}]+\})/g, '')

            fn = Function('map', `return \`${sanitized}\``)
            cache[template] = fn
        }

        return fn
    }

    return generateTemplate
}())

export default generateTemplateString
jacoballenwood
  • 2,787
  • 2
  • 24
  • 39