webpack-contrib / i18n-webpack-plugin

[DEPRECATED] Embed localization into your bundle
MIT License
317 stars 74 forks source link

I18N for HTML fragments #46

Open aikar opened 7 years ago

aikar commented 7 years ago

per #26 It's almost guaranteed anyone doing a serious I18N roll out will run into a scenario like this:

Hello {user}, Please <a href={dial}>call</a> or <a href={mailto}>email</a> us for support

This plugin currently offers no native way to create this as a single i18n string for translation.

Breaking it up into

Hello
Please
call
or
email
us for support

Is not a valid solution as the order of the words are likely to change in other languages. This needs to be handled as a single string.

In React, I created a work around seen here: https://github.com/webpack-contrib/i18n-webpack-plugin/issues/26#issuecomment-286724094

But this required us to use the dangerous inner html of React and uglifies the code writing HTML inside of strings.

We need a solution for this problem so that this plugin can be a complete i18n solution (along with #6)

Proposal: JS comment tags? JSX example


const str = 
/* @i18n */
<span>Hello {user}, Please <a href={dial}>call</a> or <a href={mailto}>email</a> us for support</span>
/* @i18n:start */;

Or maybe support:

__(<span>Hello {user}, Please <a href={dial}>call</a> or <a href={mailto}>email</a> us for support</span>)

Then of course no react environments would need consideration too.

aikar commented 7 years ago

Though, Solving this would also require this plugin to include an extractor too (which is a good idea overall), as other tools would not know how to extract it.

michael-ciniawsky commented 7 years ago

@aikar If you have time and interest to give it a shot please feel free to do so 😛

xiao-hu commented 7 years ago

I have another idea to solve this without the necessary to modify the plugin. We just need to implement a simple function say assembleAsArray which turns this assembleAsArray(__('Hello ${user}, Please ${call} or ${email} us for support'), {user: user, call : <a href={dial}>__('call')</a>, email: <a href={mailto}>__('email')</a>}) to an array ['Hello ', user, ', Please ', <a href={dial}>call</a>, ...].

And you can use it directly in React:

render() {
   <div>
      ...
      {assembleAsArray(__('Hello ${user}, Please ${call} or ${email} us for support'), {user: user, call : <a href={dial}>__('call')</a>, email: <a href={mailto}>__('email')</a>})}
      ...
   </div>
}

If you are not using React and just want to assemble strings, you can use it as well: assembleAsArray(__('Hello ${user}, Please ${call} or ${email} us for support'), {user: user, call : `<a href={dial}>${__('call')}</a>`, email: `<a href={mailto}>${__('email')}</a>`}).join('')

This could be also be a solution to #26 and #6.

zlk89 commented 7 years ago

@xiao-hu In my understanding, your idea won't solve the problem, because assembleAsArray has fixed the order of each part. But in some languages, order of each part might be different. Actually your idea is the same as solution like the one below, which simply splits one sentence into multiple separate parts. (You can see this https://github.com/webpack-contrib/i18n-webpack-plugin/issues/26#issuecomment-280917200)

__('Hello ') + ${user} + __(', Please ')...
cjol commented 6 years ago

assembleAsArray would not need to return an array with the same ordering as the input. For example:

Given this mapping: Please call ${0} or email ${1} to contact us for more information -> Pour plus de renseignements veuillez nous contacter par email au $[1} ou sur le ${0}

This code: __asArray(`Please call ${<PhoneElement />} or email ${<EmailElement />} to contact us for more information`)

Should return: `[ "Pour plus de renseignements veuillez nous contacter par email au ", , " ou sur le ",

]`