Coder Social home page Coder Social logo

Comments (20)

tricoder42 avatar tricoder42 commented on May 18, 2024 1

@cjayyy Yeah, sorry, this issues was opened almost 2 years ago. Meanwhile, react-i18next implemented similar concept with few exceptions. The main one is that they process JSX children at runtime - because of that you have to use double curly braces for variables. Unfortunately, object as a child isn't a valid JSX so some linters might not like it.

I'm closing this issue, as it was mostly discussion and it's clearly outdated.

from js-lingui.

davidfurlong avatar davidfurlong commented on May 18, 2024

@tricoder42 I felt a bit bad hijacking the thread too, but I didn't know where to take the conversation. This is good.

Reason 1: Using Trans component shifts responsibility from parent to Trans component itself. As a developer, you don't have to worry about skipped updates.

Well you shouldn't be skipping changes to the HOC passed translation props anyways, so this shouldn't pose an issue.

Second reason are inline components. Using Trans component you can go wild a do things like this:

You could theoretically return a html styled string from the function served by the translation (and then parse it) (instead of just strings, have something like:

{t["numberOfUsers"](users.length)}
...
{
en: {
numberOfUsers: (n) => `<b>${n}</b> people`
},
de: {
numberOfUsers: (n) => `personen: <b>${n}</b>`
}
}

). This would have the advantage of moving flexibility into the individual translations, and minimizing API surface area.

from js-lingui.

davidfurlong avatar davidfurlong commented on May 18, 2024

You get only one message. This is obvious, but other libs (i18next, formatjs) translate content of inline components separately which is unfortunate for translators.

What do you mean by this?

from js-lingui.

davidfurlong avatar davidfurlong commented on May 18, 2024

Any component is <0>valid</0> here, even <1>custom</1> ones.

But the translators have no idea what the tags are?

from js-lingui.

davidfurlong avatar davidfurlong commented on May 18, 2024

In future I'm planning further optimization, when message is rendered to React components tree and when props changes (like values, params) the message isn't parsed from scratch, but React handle update itself. Right now, message itself is cached, but inline components are rendered on each update.

could be solved by a memoized function

from js-lingui.

davidfurlong avatar davidfurlong commented on May 18, 2024

/ Message
<Trans>Hello World</Trans>
// becomes {'Hello World': 'Hello World'} for English

I like the way the contents automatically become the key

from js-lingui.

davidfurlong avatar davidfurlong commented on May 18, 2024

The method of using
<Trans></Trans> everywhere encourages having big translation blocks. I'm not sure whether its best principles to keep them small or not, but I'd imagine so

from js-lingui.

tricoder42 avatar tricoder42 commented on May 18, 2024

Well you shouldn't be skipping changes to the HOC passed translation props anyways, so this shouldn't pose an issue.

The component skipping update might be high above the HOC. It might not even be aware of some i18n going on down in tree. This is common bug in formatjs and I guess other libs too: You switch language, but not all translations are updated. So they recommend to reload the page, to avoid any problems, but it's unnecessary.

You could theoretically return a html styled string from the function served by the translation (and then parse it)

I'm working on sth similar. lingui-cli will have a compile method, which takes ICU message format and returns a function. In the app, you only pass a formatting function with all data in clojure, so you don't use messageformat parser in browser (slow, heavy). Then you can load compiled catalogs, save a few kb and gain perf.

You get only one message. This is obvious, but other libs (i18next, formatjs) translate content of inline components separately which is unfortunate for translators.

What do you mean by this?

This is how does in react-intl (taken from example in docs: https://github.com/yahoo/react-intl/wiki/Components#string-formatting-components):

<FormattedMessage
    id='app.greeting'
    description='Greeting to welcome the user to the app'
    defaultMessage='Hello, {name}!'
    values={{
        name: <b>Eric</b>
    }}
/>

They replace all inline components with variables and pass React component as a variable. So, either the Eric isn't translated (not problem in this usecase), or you can pass another FormattedMessage, but then you'll get two messages, instead of one:

<FormattedMessage
    id='app.greeting'
    defaultMessage='Read {more}'
    values={{
        more: <a href="/more"><FormattedMessage defaultMessage="more" /></a>
    }}
/>

Any component is <0>valid</0> here, even <1>custom</1> ones.

But the translators have no idea what the tags are?

That's my concert too! I was thinking about <0:strong> or <1:a>, so the translator knows a bit what tag is there, but props are still kept away. Everything after : is just a comment, the important is index of component. What do you think?

The method of using
everywhere encourages having big translation blocks. I'm not sure whether its best principles to keep them small or not, but I'd imagine so

This depends. I'm not a translator, but I think the smallest unit should be a paragraph. That's what holds the context. Some SaaS use sentence as the smallest unit. I'm not against it, but I guess that if you translate a paragraph, you only rarely do 1:1, sentence by sentence translation. In UI translatios it usually doesn't matter.

Definitely I don't what to translate Read <a>more</a> as two separate words :) Never break a sentence into words.

from js-lingui.

davidfurlong avatar davidfurlong commented on May 18, 2024

The component skipping update might be high above the HOC. It might not even be aware of some i18n going on down in tree. This is common bug in formatjs and I guess other libs too: You switch language, but not all translations are updated. So they recommend to reload the page, to avoid any problems, but it's unnecessary.

I suppose this could be the case, but it seems you have written bad shouldComponentUpdate methods if you are stopping rerender propagation for the entire subtree when the change in props does need to propagate.

They replace all inline components with variables and pass React component as a variable. So, either the Eric isn't translated (not problem in this usecase), or you can pass another FormattedMessage, but then you'll get two messages, instead of one:

Ah I see. Yes this is an eye sore and I don't want this kind of crap in my codebase.

That's my concert too! I was thinking about <0:strong> or <1:a>, so the translator knows a bit what tag is there, but props are still kept away. Everything after : is just a comment, the important is index of component. What do you think?

Well thats committing each translation to using the same HTML elements. It also seems like its adding ugly complexity. Occasionally you do want to "yield" and nest another component or translation within another - think popover on hover on a word in a paragraph - but that word could be located anywhere - this is why intl libraries are so damn complex.

At this point I may just bite the bullet and use a complex intl library

Also wouldn't the below code from your readme generate a new translation key for each value of name passed to it? - or are you doing this before runtime and stringifying the Trans contents?

// Variables
        <Trans>Hello, my name is {name}</Trans>

from js-lingui.

davidfurlong avatar davidfurlong commented on May 18, 2024

I threw together a little proof of concept

https://github.com/DeedMob/react-local-translations

Will add dynamic language asap

from js-lingui.

tricoder42 avatar tricoder42 commented on May 18, 2024

I suppose this could be the case, but it seems you have written bad shouldComponentUpdate methods if you are stopping rerender propagation for the entire subtree when the change in props does need to propagate.

The problem is that language/messages are passed in context and only the last component receives it from HOC as props. Updates in context needs to be handled carefuly, as described here https://medium.com/@mweststrate/how-to-safely-use-react-context-b7e343eff076#.mohyrubc7

Well thats committing each translation to using the same HTML elements. It also seems like its adding ugly complexity. Occasionally you do want to "yield" and nest another component or translation within another - think popover on hover on a word in a paragraph - but that word could be located anywhere - this is why intl libraries are so damn complex.

Yes, sometimes it makes sense and it's possible:

<Trans>
   Click <Popover
       header={i18n.t`Payment options`}
       body={
           <Trans>Please select payment options</Trans>
       }>here</Popover> to set payment options.
</Trans>

This will result in three messages:

  1. "Click <0>here</0> to set payment options."
  2. "Payment options"
  3. "Please select payment options"

Each of them make sense on it's own. You can decouple messages from UI.

However, I never thought about a use case, where you use different components in different languages. Something like <0>Hello</0> in English, but <1>Hola</1> in Spanish, where 0 and 1 are different components. Technically it's possible with current solution, it's just not implemented yet.

Also wouldn't the below code from your readme generate a new translation key for each value of name passed to it? - or are you doing this before runtime and stringifying the Trans contents?

No, just one. You need to use babel-plugin-lingui-transform-react or babel-plugin-lingui-transform-js to make it happen. However, lingui-i18n is based on template strings which are ES6 feature and lingui-react is based on JSX, so you need babel anyway (in most cases).

from js-lingui.

davidfurlong avatar davidfurlong commented on May 18, 2024

The problem is that language/messages are passed in context and only the last component receives it from HOC as props. Updates in context needs to be handled carefuly, as described here https://medium.com/@mweststrate/how-to-safely-use-react-context-b7e343eff076#.mohyrubc7

You're totally right. Thanks for telling me this, I haven't used React's contexts.

Yeah everyone will have babel anyways.

I have updated my mini localized components library to reflect this change and I'm quite happy with it. Demo @ https://deedmob.github.io/react-local-translations/example/index.html
Of course I'm not sure how well it will perform, but it suits my needs quite well

from js-lingui.

tricoder42 avatar tricoder42 commented on May 18, 2024

@davidfurlong That's a good stuff! I'm a bit busy this week with other projects, but I'm going to push custom formats this weekend. I'll take a look at local catalogs after that.

from js-lingui.

ivan7237d avatar ivan7237d commented on May 18, 2024

Reg. user-provided versus autogenerated IDs: I'm wondering if by adding support for "description" prop you would end up with the best of both worlds. If you autogenerate IDs as a hash of description + default message, you will be able to avoid clashes between short default messages that mean different things in different contexts.

Also I wonder if it would make sense to create an "Argument" HOC that will have also have a description and which could be used to wrap child components - it would pass on its child but will add the description that will help translators understand what the child component is.

from js-lingui.

ivan7237d avatar ivan7237d commented on May 18, 2024

Actually what would be even more fun is using the jsdoc comments as descriptions for messages and message arguments.

from js-lingui.

tricoder42 avatar tricoder42 commented on May 18, 2024

Hello Ivan 👋

Actually what would be even more fun is using the jsdoc comments as descriptions for messages and message arguments.

Good point, I'm planning to add comments for translators, something like this:

const Label = () =>
  // i18n: Heading at registration page
  <h1><Trans>Registration</Trans></h1>

which would be extracted as:

{
  "Registration": {
    "description": "Heading at registration page",
    "translation": ""
  }
}

It could be probably possible to add description prop directly to <Trans> component, but it JS it would become more verbose: i18n.t('Registration', { description: "Heading at registration page" }). I'm open to any ideas and PRs here!

Also I wonder if it would make sense to create an "Argument" HOC that will have also have a description and which could be used to wrap child components - it would pass on its child but will add the description that will help translators understand what the child component is.

Could you please provide a short example of this?

Thank you!

from js-lingui.

ivan7237d avatar ivan7237d commented on May 18, 2024

Hey Tomáš, yes, the comments approach sounds good, better than a prop. And as for arguments, if you have

<Trans>Abc<MyComponent /></Trans>

then as far as I understand, currently the translation file will just have a number for <MyComponent />, and ideally you'd want to let the translators know what <MyComponent /> is, so I was thinking of ways to achieve that. Here too, a comment would be nicer than a wrapper component with a prop, but JSX doesn't support comments, so I can't think of some good approach off the top of my head...

from js-lingui.

tricoder42 avatar tricoder42 commented on May 18, 2024

I see. Maybe we could use description for it:

// i18n: <Link> - clickable element
<Trans>Link to <Link>documentation</Link></Trans>

and extracted description might be:

{
  "Link to <0>documentation</0>": {
    "description": "<0> - clickable element",
    "translation": ""
  }
}

What do you think?

from js-lingui.

ivan7237d avatar ivan7237d commented on May 18, 2024

Hmm... I wonder if this is general enough. For example there could be multiple child components with the same name but different props or different children. Maybe this would work, looks a bit ugly but it's the usual way to add comments in JSX:

<Trans>Link to {/* i18n: Clickable element */}<Link>documentation</Link></Trans>

from js-lingui.

cjayyy avatar cjayyy commented on May 18, 2024

Reason 1: Using Trans component shifts responsibility from parent to Trans component itself. As a developer, you don't have to worry about skipped updates.

Second reason are inline components. Using Trans component you can go wild a do things like this:

<Trans>
   Any component is <strong className="green">valid</strong> here, even <Link>custom</Link> ones.
</Trans>

Example above will result in single entry in your message catalog: Any component is <0>valid</0> here, even <1>custom</1> ones.

This has several advantages:

  1. Translator doesn't care about html tags
  2. Props of inline components doesn't affect message
  3. You get only one message. This is obvious, but other libs (i18next, formatjs) translate content of inline components separately which is unfortunate for translators.

According to i18next docs this doesn't seem to be up-to-date. In their example sandbox complex message extraction results into one piece.

from js-lingui.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.