jenseng / react-i18nliner Goto Github PK
View Code? Open in Web Editor NEWtranslate="yes" all the things
License: MIT License
translate="yes" all the things
License: MIT License
This doesn't really affect functionality, but it does make for nicer translation strings... Consider:
<p translate="yes">Hello <b><i>{user}</i></b></p>
Currently that yields the translation string:
"Hello ** *%{user}* **"
The double wrappers add no value for translators, and are more likely to get screwed up. We should coalesce them so that the translators see:
"Hello *%{user}*"
i18nliner-handlebars and canvas_react_i18n both do this, we should too.
Even better would be no wrappers, if all that is contained is a placeholder, but we can save that for another ticket ๐
Per the spec ... if a translatable attribute has literal text, and its element (or ancestor) has translate="yes"
, we should preprocess that into an I18n.t
call. If the element (or ancestor) has translate="no"
, we should not. Non-translatable attributes should never be preprocessed into I18n.t
calls.
Example:
<p translate="yes">
Update your preferences <a href="/prefs" title="User Preferences">here</a>.
</p>
This would result in the strings "Update your preferences *here*"
and "User Preferences"
being extracted/translated, but of course "/prefs"
would not.
this is complementary to #1 ... we should remove extraneous whitespace from the extracted string if it's content (not an attribute), since whitespace is not significant in html ... basically .replace(/\s+/g, ' ').trim();
, just line i18nliner-handlebars does
Using {" "}
is a very common way to add a white-space, however when used with react-i18nliner it causes a failure to compile.
to facilitate debugging, we should preserve whitespace (or at least newlines) when converting a translate="yes"
component to a <ComponentInterpolator>
... that way line numbers will match up with the original source. as it stands right now, recast is injecting some newlines, presumably for readability.
we handle this kinda rudimentarily in i18nliner (erb)
this is a plugin; we want it installed alongside i18nliner. if it's a dependency, react-i18nliner might get its own i18nliner, and thus not plug in to the top-level one :'(
Hi John! ๐
I ran into an error cannot read property 'noParse' of undefined
after upgrading to webpack 3. It seems that this.options.module
is now undefined ๐ข . Looking over the docs on webpack loaders (https://webpack.js.org/contribute/writing-a-loader/) it seems they discourage accessing the options directly, and they even go so far as to say that options is read-only.
I was able to get things working by explicitly adding the noParse
rule to my config:
noParse: /i18nliner\/dist\/lib\/i18nliner/,
and creating a simpler version of your webpack loader that doesn't set the noParse
config anymore:
const I18nliner = require('i18nliner').default;
const hasTranslatableText = require('react-i18nliner/hasTranslatableText')(I18nliner.config);
const preprocess = require('react-i18nliner/preprocess');
module.exports = function i18nloader(source) {
this.cacheable();
if (hasTranslatableText(source)) {
return preprocess(source, I18nliner.config);
}
return source;
};
I'm not sure if there's still a way to automatically set the noParse
config from within the loader.
react-i18nliner lets you stick translate="yes"
on anything, which is cool. But what would be really cool is if you could basically say "auto translate these tags/components unless they have a translate="no"
. In my mind, that's pretty much the holy grail of i18n ... you get to a point where you (almost) never have to do anything or even think about i18n; your app is just automagically localized.
For starters this could be an opt-in thing, by way of .i18nrc
... basically have a setting of the elements/components that should be auto-translated. Some sensible ones to turn on would be <p />
, <th />
, <label />
, <h1 />
, etc. You probably would not want to do it for <div />
or <span />
This is also nice because it makes for an easy upgrade path from canvas_react_i18n ... just create a <Text />
component that just renders its content, and set it to auto-translate.
It is a bit of a can of worms though, i.e. it dramatically increases the likelihood of nested translatable elements. In some cases you probably only want to translate the outer one (e.g. (<p>see the <a href="/">index</a></p>
). We should probably make that happen automatically, if there are no intermediate non-translatable elements.
So that gets to a second point, you might need a list of auto-don't-translates ... Consider: <label>I live in <select placeholder="state"><option>Alabama<option>Alaska...
... it would be nice to set <label />
and <option />
to auto-translate, and <select />
to never translate. Then you'd get a string for the label text (plus placeholder), and a string for each state.
given:
<div translate="yes">
Your Score
<b className="learnerScore">{score}</b><span className="superscript">%</span>
</div>
you get a placeholder for <b>
and a wrapper for the <span>
, and they both get key="1"
... keys should be unique across interpolated wrapper and placeholder components
right now react-i18nliner doesn't play nicely with i18nliner-js' JsProcessor or the i18n-js runtime, because it generates I18n.t
calls with placeholders that have no corresponding values. strictly speaking there are values, but not in the I18n.t
arguments, they are props of the <I18n.ComponentInterpolator>
a quick fix that would obviate the need for changing i18nliner-js or i18n-js would be to simply have dummy placeholder values that put the placeholder right back, e.g. user="%{user}"
. long term though it'd be great if i18nliner-js/i18n-js supported it (e.g. translateWithoutInterpolation
, or change lookup
to support a string-instead-of-key and make it extractable)
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,
I don't expect you to fix this, but it would be nice if this was documented, so I'm preparing a PR to update the docs.
if a placeholder value is missing, you get <ComponentInterpolator> expected '${token}' placeholder value, none found
... right now it just does a falsy check, which is way too broad. instead we should see if it's present in props. if it is present, we should not raise an error, even if the value is undefined/null/false/0/""
c:\ws\react-i18nliner> npm test
> [email protected] test c:\ws\react-i18nliner
> eslint . && node_modules/.bin/jest
'node_modules' is not recognized as an internal or external command,
operable program or batch file.
npm ERR! Test failed. See above for more details.
I'll prepare a PR to fix this.
given:
<div translate="yes">
Your Score
<b className="learnerScore">{score}</b><span className="superscript">%</span>
</div>
the pre-processed representation is:
<div>
<I18n.ComponentInterpolator
string={I18n.t("Your Score %{score} *%*", { "score": "%{score}" })}
wrappers={{ "*": <span className="superscript">$1</span> }}
score={<b className="learnerScore">{score}</b>}
>$1</I18n.ComponentInterpolator>
</div>
note the whitespace between the score and the % ... we shouldn't introduce any whitespace not in the source. for adjacent placeholders this isn't a big deal, but it could be an issue for parsing wrappers (especially when dealing with nesting/etc.) ... might need to use different delimiters :'(
Hi, doing npm install for the project I'm getting this warning:
(master) % cd react-i18nliner ~/towbook
(master) % npm install ~/towbook/react-i18nliner
npm WARN package.json [email protected] No repository field.
npm WARN engine [email protected]: wanted: {"node":"0.8.x || 0.10.x"} (current: {"node":"0.12.4","npm":"2.10.1"})
npm WARN deprecated [email protected]: react-tools is deprecated. For more information, visit https://fb.me/react-tools-deprecated
npm WARN prefer global [email protected] should be installed with -g
Spawned from #3
If all that a wrapper contains is a placeholder (no text content), we should not create a wrapper and should instead merge its component(s) into the placeholder value, e.g. consider:
<p translate="yes">Hello <b>{user}</b></p>
Ideally that should yield the following (note the lack of wrapper):
"Hello %{user}"
The value for %{user}
would be <b>{user}</b>
I'm getting this warning when I run my tests:
Warning: Accessing createClass via the main React package is deprecated, and will be removed in React v16.0. Use a plain JavaScript class instead. If you're not yet ready to migrate, create-react-class v15.* is available on npm as a temporary, drop-in replacement. For more info see https://fb.me/react-create-class
It's being used in the definition of ComponentInterpolator
. It looks from a cursory investigation like ComponentInterpolator
could become a pure functional component if we were to pass keyCounter
along when we recursively call interpolateAllComponents
.
Hi,
all my react components are in files with .jsx extension, but I don't know how to make processed those files :(
Best Regards.
Another thing for nicer translation strings... Consider:
<button onClick={this.close}>
<Icon className="i-close" />
<span translate="yes">Close</span>
</button>
The span is superfluous, but if we put translate="yes"
on the <button />
then translators will see a placeholder for the <Icon />
, which is not helpful.
If a wrapper has leading or trailing elements with no text content, we should absorb them into the wrapper. Then you can safely do:
<button onClick={this.close} translate="yes">
<Icon className="i-close" />
Close
</button>
an the extracted string will just be:
"Close"
i18nliner-handlebars and canvas_react_i18n both do this, we should too.
right now it does a couple things when inferring a placeholder key from an expression:
this.
, this.props.
, and this.state.
prefixesin addition it would be great to also:
this.
, this.props.
, and this.state.
anywhere, not just in prefixesthe webpack loader and browserify transform will do a full preprocess of every file they are given ... that means an esprima/acorn parse, a recast visit, and a recast print. we should skip files if we know we don't need to process them
we already have logic that does this for i18nliner:check ... a simple regex check for translatable content (based on .i18nrc settings)
this may be a recast printing bug, or it may be due to #1, or both ... i've got a file w/ some jsx like so
<div>
<LayoutItemHeader type="survey">
...
<Block name="layout--item-header__actions">
<SurveyHeaderActions
survey={this.props.survey}
permissions={this.props.permissions}
media={this.state.media}
handleClickPreview={this.handleClickPreview}
handleDuplicate={this.handleDuplicate} />
</Block>
</LayoutItemHeader>
<div className="survey-distributions large-content-area centered padding-trl-m-desktop padding-none-mobile">
<div key="subtitle" className="clearfix padding-tb-l padding-xs-mobile grey-bg-mobile">
<h2 className="margin-b-s left">
{I18n.t("Distributions")}
</h2>
<DistributeBox groupSearch={this.props.groupSearch} surveyId={this.props.survey.id}>
<button type="button" className="add-btn">
<Text>+ <span className="add-btn__text">Distribute</span></Text>
</button>
</DistributeBox>
</div>
<DistributionList {...distributionProps} />
</div>
</div>
it gets preprocessed into this:
<div>
<LayoutItemHeader type="survey">
...
<Block name="layout--item-header__actions">
<SurveyHeaderActions
survey={this.props.survey}
permissions={this.props.permissions}
me dia={t<I18n.ComponentInterpolator
string={I18n.t("+ *Distribute*")}
wrappers={{
"*": s.state.media}$1
}}>$1</I18n.ComponentInterpolator>
handleClickPreview={this.handleClickPreview}
handleDuplicate={this.handleDuplicate} />
</Block>
</LayoutItemHeader>
<div className="survey-distributions large-content-area centered padding-trl-m-desktop padding-none-mobile">
<div key="subtitle" className="clearfix padding-tb-l padding-xs-mobile grey-bg-mobile">
<h2 className="margin-b-s left">
{I18n.t("Distributions")}
</h2>
<DistributeBox groupSearch={this.props.groupSearch} surveyId={this.props.survey.id}>
<button type="button" className="add-btn">
<Text>+ <span className="add-btn__text">Distribute</span></Text>
</button>
</DistributeBox>
</div>
<DistributionList {...distributionProps} />
</div>
</div>
<Text>
is an autoTranslateTag, and it does get preprocessed ... sort of, but in the wrong place. note the mangled media
attribute inside <SurveyHeaderActions>
... totally broken
Hello, I'm trying to follow the readme but I can't seem to make it work, is there any project sample(folder) that can be followed?
This could provide a mechanism to specify a friendlier placeholder, rather than letting it be inferred. For example:
<p translate="yes">
Create <input onChange={this.createAccounts} /> new user accounts
</p>
Currently this yields "Create %{input_on_change_this_create_accounts} new accounts"
, which is terrible, and likely to change.
If we used the key, you could do this:
<p translate="yes">
Create <input key="numAccounts" onChange={this.createAccounts} /> new user accounts
</p>
then the string could just be "Create %{num_accounts} new accounts"
Hi,
Seems react-i18nliner is not supporting ES6 classes?
ERROR in ./src/client.js
Module parse failed: /Users/erik/project1/node_modules/babel-
loader/index.js!/Users/erik/project1/node_modules/react-i18nliner/webpack-
loader.js!/Users/erik/project1/src/client.js Line 5: Unexpected reserved word
You may need an appropriate loader to handle this file type.
| import React from 'react';
Anyway to force a language for localization?
I assume by default, browser language is picked up.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.