Closed ikhilko closed 8 years ago
It's non-obvious because of how the string is first processed, but you need four backslashes:
<FormattedMessage id="someId" defaultMessage="My message (one\\\\two\\\\three)"/>
That said, I believe there is a bug here that I can fix in this plugin. The default message strings will be processed as part of the extraction process and end up with the following value in the JSON file:
[
{
"id": "someId",
"defaultMessage": "My message (one\\two\\three)"
}
]
While the message left in the source file will still contain the four backslashes. This could mean that when falling back to the default message in source (because the translation wasn't loaded or passed in to <IntlProvider>
), the result in the UI would contain double backslashes, instead of the desired single backslash. Whether or not this is the case is in how Babel handles the files during transpilation. If Babel leaves the original string in the source with the four backslashes, then I'll update the plugin to fix that.
I also realized that I haven't released intl-messageformat-parser
which supports backslashes… I'll ping this thread again when I have.
https://github.com/yahoo/intl-messageformat-parser/compare/v1.1.0...master
@ikhilko Thanks again for pointing this out. I spent a good part of the day revamping how backslash-escaping works for extracting messages, and it's now corrected. I've released intl-messageformat-parser@1.2.0
which adds support for escaping backslashes themselves. I will work on releasing an updated version of this plugin and React Intl v2 tomorrow.
babel-plugin-react-intl@1.0.0-beta-5
has been released which fixes this escaping issue.
Sounds good! Thank you
@ericf, i have a question again... I'm just checked out babel-plugin-react-intl@1.0.0-beta-5
and try it. And again a have a question how to use backslashes in my sources.. If I want a single backslash in my message what I need to write in JSX?
<FormattedMessage id="someId" defaultMessage={"one \ two"}/> escapes space symbol
<FormattedMessage id="someId" defaultMessage={"one \\ two"}/> error in this plugin
<FormattedMessage id="someId" defaultMessage={"one \\\ two"}/> error in this plugin
<FormattedMessage id="someId" defaultMessage={"one \\\\ two"}/> \\\\ transformed to \\\\ in json
and again
<FormattedMessage id="someId" defaultMessage="one \ two"/> escapes space symbol
<FormattedMessage id="someId" defaultMessage="one \\ two"/> \\ transformed to \\\\ in json
<FormattedMessage id="someId" defaultMessage="one \\\ two"/> error in this plugin
<FormattedMessage id="someId" defaultMessage="one \\\\ two"/> \\\\ transformed to \\\\\\\\ in json
My expectations was that plugin will do it like JS do. No matter I use {""} or "" syntax:
"one \ two" transformed to json as is "one \ two" (escape space)
"one \\ two" transformed to json as is "one \\ two" (single backslash)
"one \\\ two" transformed to json as is "one \\\ two" (single backslash)
"one \\\\ two" transformed to json as is "one \\\\ two" (double backslash)
Please, can you correct me?
@ikhilko intl-messageformat-parser
requires double backslashes to escape things, otherwise the escaping intent would be lost in translation (sorry I couldn't help myself), and needs this to escape ICU Message syntax characters.
In JavaScript strings: "\{" === "{"
, so we need a way to express the intent that you want the curly brace (which is a ICU Message syntax character) to not be interpreted when parsing. That's why the double backslash is required: "\\{"
This then extends into how to tell the parser not to interpret "\\"
as the beginning of an escape sequence so a literal backslash character can be displayed. To do this we need to double-escape the backslashes which is why "\\\\"
is interpreted by the parser as "\\"
which when rendered will display: \
Strings defined in JSX are parsed like HTML/XML strings, not JavaScript strings; this means they are double-escaped. Depending on which string you're creating (JavaScript or JSX) you need a different amount of backslashes.
Using JSX Strings:
<FormattedMessage id="someId" defaultMessage="one \\ two" />
When the JSX string "one \\ two"
is parsed, it's value as a JavaScript string is actually: "one \\\\ two"
and therefore can be properly parsed by intl-messageformat-parser
. If this JSX string wasn't going to be parsed as an ICU Message, then you could define it as: "one \ two"
.
Using JavaScript Strings:
<FormattedMessage id="someId" defaultMessage={"one \\\\ two"} />
I hope this makes some sense as to why we're doing escape sequences this way for ICU Message strings. Also I just released an updated React Intl which uses the latest version of intl-messageformat-parser
that now supports escaping backslashes themselves. Update to react-intl@2.0.0-beta-1
.
Thanks, you for detailed explanation of how it work. Now it more clear for me.
@ericf Thank you very much for your answer. I am having a problem that may be related:
I have posted a question on stackoverflow here with the details. I have inlined the question into this comment as well. Thank you in advance for any assistance.
Summary
When I load my app using Webpack Dev Server, my messages show up fine:
\
. However when I bundle the application to disk and server the bundle vianginx
, I see a duplication of my backslash:\\
.
Details
I am using react-intl
@2.2.3 (latest at this time) and babel-plugin-react-intl
@2.3.1 (latest at this time.) My goal is to define a default message with a \
character and render it in any way (FormattedMessage
, formatMessage
, etc)
I am bundling my app using Webpack / Babel. I have no Babel / react-intl specific config in my webpack.config.js
file, however I do use DefinePlugin
to set process.env
to 'development'
or 'production'
When I load my app using Webpack Dev Server, my messages show up fine: \
. However when I bundle the application to disk and serve the bundle via nginx
, I see a duplication of my backslash: \\
. I have following instructions here: https://github.com/yahoo/babel-plugin-react-intl/issues/13#issuecomment-151944191 with regard to using 4 \
characters to show a final \
character.
For what it is worth, I have tried using JSX strings, JS strings, using 1, 2, and 4 \
characters, and any other silly combinations I could think of.
Any tips or suggestions are greatly appreciated. Thank you.
Code samples
An example of how I define messages
import { defineMessages } from 'react-intl'
export default defineMessages({
message: {
id: 'anyId',
defaultMessage: '\\\\',
},
})
An example of how I might render my messages
<FormattedMessage { ...messages.anyID } /></span>
Another example, which also does not work
<FormattedMessage id='anyId' defaultMessage='\\' />
Yet another failing example:
<FormattedMessage id='anyId' defaultMessage={ '\\\\' } />
When I'm trying to use backslash in my values (defaultMessage) in JSX, like this:
Plugin raises:
So it's looks like I cannot use \ symbol in JSX value. Any suggestions?