jenseng / react-i18nliner

translate="yes" all the things
MIT License
45 stars 15 forks source link

Using it with react_templates #18

Open ekaradon opened 9 years ago

ekaradon commented 9 years ago

Hello,

I try to use this library in my application and I have a little issue. Indeed, I am using the (https://github.com/wix/react-templates)[react templates library] and it is using the extension .rt and not the .js or the .jsx extension. And I do not find how-to configure .i18nrc in order to change this pattern.

Cheers,

Sy1v4in commented 9 years ago

Hi @jenseng,

i have a fix for this problem. The AbstractProcessor uses a pattern to get files which could be configured (through the options). But, in the i18nliner checks comment (file i18nliner-js/dist/lib/commands/check.js) you omit to transmit the configured pattern to the Processor in order to go through files you want:

      pattern: this.options.pattern,

In this case @ekaradon should call i18nliner export --pattern='*.rt' to make it work in his specific react templates context.

I create the https://github.com/jenseng/i18nliner-js/pull/18 PR in the i18nliner-js project to fix that.

Cheers

jenseng commented 9 years ago

@fraisse Thanks for the PR, I'll check it out!

@ekaradon Though even with that PR, I suspect react-i18nliner won't work in its current form with react-templates, since it preprocesses JSX, not HTML (I'm fairly certain both esprima and acorn would choke on .rt, and recast definitely would not generate valid .rt). Also, react-i18nliner uses the same processor for both regular .js files as well as .jsx (since JSX is a superset of JS). So I think we'd probably need a brand new pre-processor for .rt files.

That said, you should be able to use i18nliner-js today via javascript expressions, e.g.

<h1>{I18n.t("Hello World")}</h1>

Note that you'll want to run the i18nliner check and export commands on the javascript files generated by react-templates, not on the original .rt files.

ekaradon commented 9 years ago

@jenseng Thanks for the answer,

Indeed, it does not work. It is stuck with an error complaining about a malformed string:

Error: Line 3: Adjacent JSX elements must be wrapped in an enclosing tag
[...]/node_modules/react-i18nliner/node_modules/recast/node_modules/esprima-fb/esprima.js:7736
           throw e;
   at throwError ([...]/node_modules/react-i18nliner/node_modules/recast/node_modules/esprima-fb/esprima.js:2819:21)
   at parseJSXElement ([...]/node_modules/react-i18nliner/node_modules/recast/node_modules/esprima-fb/esprima.js:7226:13)
   at parsePrimaryExpression ([...]/node_modules/react-i18nliner/node_modules/recast/node_modules/esprima-fb/esprima.js:3590:20)
   at parseLeftHandSideExpressionAllowCall ([...]/node_modules/react-i18nliner/node_modules/recast/node_modules/esprima-fb/esprima.js:3683:61)
   at parsePostfixExpression ([...]/node_modules/react-i18nliner/node_modules/recast/node_modules/esprima-fb/esprima.js:3723:20)
   at parseUnaryExpression ([...]/node_modules/react-i18nliner/node_modules/recast/node_modules/esprima-fb/esprima.js:3790:16)
   at parseBinaryExpression ([...]/node_modules/react-i18nliner/node_modules/recast/node_modules/esprima-fb/esprima.js:3880:16)
   at parseConditionalExpression ([...]/node_modules/react-i18nliner/node_modules/recast/node_modules/esprima-fb/esprima.js:3940:16)
   at parseAssignmentExpression ([...]/node_modules/react-i18nliner/node_modules/recast/node_modules/esprima-fb/esprima.js:4193:16)
   at parseExpression ([...]/node_modules/react-i18nliner/node_modules/recast/node_modules/esprima-fb/esprima.js:4250:16)

But I am not sure about what it would take to make it work and what need to be done. Is it possible to get further explanations about the pre-processing thing?

Also, I would like to know what the pre-processing outputs. I first thought that it was transforming the balise from:

<h2 translate="yes"> My title</h2>

to:

{i18n.translate("my_title")}

But if such was the case, It would works with esprima without complaints.

ekaradon commented 9 years ago

Hello,

Would it be possible to get some clues about this topic? I am hesitating between using react-intl8 and this project but I would prefer to use this last one because the syntax is nicer. However, I am a bit stuck with this error of compilation and as I have no idea about how long it would take to support react-templates, I am in the dark.

ailonn commented 9 years ago

Hello, I just met this complication on working on my project. What is the fix planning ? Thanks you for your work !

jenseng commented 9 years ago

@ekaradon / @ailonn: sorry for the delayed response, I've had a busy couple weeks...

react-i18nliner parses javascript files to find JSX elements with translate attributes. It expects the file to be valid JSX, and by default it uses esprima to do the parsing (though you can also use acorn). Although react-templates are similar to JSX, they are not equivalent, and thus will not be handled correctly by esprima or acorn. Key differences include class vs className, case-sensitivity of properties, attribute quoting, JSX's requirement that adjacent elements be nested in another one (that's the error you're seeing), etc.

So in its current state, there's not currently any way to use react-i18nliner on an .rtl file. And unfortunately, I don't have any immediate plans to support it. That said, I'd be happy to entertain pull requests that do add support. Though ideally, I think it would make even more sense as a separate NPM module (e.g. react-templates-i18nliner), and I'd be happy to provide some direction on how to go about it. react-templates uses cheerio to parse the HTML in your .rtl file into a tree, and then generates javascript from it.

So for react-templates-i18nliner, it seems like you would want to:

  1. Build a pre-processor that loads the DOM tree from your .rtl file via cheerio (just like react-templates does), and converts components w/ translate="yes" into I18n.ComponentInterpolators (see tests here). Ideally it would output .rtl back out, which react-templates would then covert into .js. This pre-processor would need to be used in your build process before react-templates runs.
  2. Build an i18nliner processor (using the pre-processor above) that extracts strings from those elements, so that they are picked up when you run i18nliner check or i18nliner export.

The pre-processor would have a lot of parallels to react-i18nliner's, the fundamental difference being it would operate on a cheerio tree instead of an esprima AST.

All that said, you should be able to use i18nliner as-is (e.g. <h2>{I18n.t("My Title")}</h2>), provided that you are running i18nliner check on the files after they're converted from .rtl to .js. From your error, it sounds like you're running i18nliner on the original .rtl files, which won't work due to the aformentioned incompatibilities between .rtl and .jsx. I don't know how you're building your assets (grunt/gulp/webpack/broccoli), but you'd want to point i18nliner at the intermediate or final .js files (since esprima/acorn cannot parse .rtl files). So you should probably 1. skip any hacks you have to process .rtl files and 2. tweak your .i18nrc to point at the files that have already been compiled by react-templates (maybe a tmp, dist, or public dir), e.g.

{
  "directories": ["dist"],
}

I hope that helps!

ekaradon commented 9 years ago

@jenseng, thanks for your answer. It did help me to see more clearly how it works. However, after thinking about it, I have decided to restart the project using only JSX through function which is imported from a different file in order to keep my definition of html outside of the component itself.

Indeed, react-templates was giving me some real headaches using it with different libraries like yours, react-router or even worse was giving me new bugs that pure JSX have not (like ignoring setting disabled).

Anyway, the problem is solved for my part and I will be using your library. I let you choose if you want to close this ticket or let it opened for newcomers.

Cheers!