Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support React Native easily #600

Closed
steida opened this issue Aug 17, 2016 · 55 comments
Closed

Support React Native easily #600

steida opened this issue Aug 17, 2016 · 55 comments

Comments

@steida
Copy link

steida commented Aug 17, 2016

The only problem with usage in React Native is span inside components. React Native needs Text. We can fix it easily. Add textElement into intlConfigPropTypes.

// In React Native
<IntlProvider
  textElement={Text}
  // ...
/>

Then all components can use textElement from the context if available.

@steida steida mentioned this issue Aug 17, 2016
@jrylan
Copy link

jrylan commented Aug 17, 2016

100% agree with this approach.

@ericf
Copy link
Collaborator

ericf commented Aug 17, 2016

Sure, want to PR this? also s/Element/Component/

@ericf
Copy link
Collaborator

ericf commented Aug 17, 2016

The other thing this approach can help with is using the <Formatted*> components within SVGs. Since a nested <IntlProvider> inherits from its parent, it would be a cheap easy way to solve the issue of <span>s not being allowed in SVGs.

@steida
Copy link
Author

steida commented Aug 17, 2016

It's safe to write only <IntlProvider textElement={Foo} />?

@steida
Copy link
Author

steida commented Aug 17, 2016

There are two another issues for universal react-intl:

Can I send it in one pull request?

This was referenced Aug 17, 2016
@ericf
Copy link
Collaborator

ericf commented Aug 18, 2016

That's because style inheritance is not safe nor explicit, so style prop is the must.

This sort of sucks as it breaks the abstraction.

All components must provide setNativeProps method

Can it just be a function that forwards the call onto the <Text> child?

@steida
Copy link
Author

steida commented Aug 18, 2016

Which abstraction it breaks?
Yes, it's just a forward https://github.com/este/este/blob/master/src/native/app/components/Text.react.js#L34

@steida
Copy link
Author

steida commented Aug 19, 2016

As for style inheritance. I think I was wrong. A browser can inherit them and the Text component in React Native inherits as well. http://facebook.github.io/react-native/releases/0.31/docs/text.html#nested-text

I had some issues with that, but I need to investigate it more.

@ericf
Copy link
Collaborator

ericf commented Aug 19, 2016

Which abstraction it breaks?

Sebastian has a good talk on this: https://www.youtube.com/watch?v=Zemce4Y1Y-A

A browser can inherit them and the Text component in React Native inherits as well.

Okay that's much better and matches what I remember about React Native. I don't want to introduce a style prop on all of the React Intl components.

@steida
Copy link
Author

steida commented Aug 19, 2016

I see, still, the text styles seem to be universal among React and React native. But you are right, it could be abstracted. Have you read this awesome article?

Notice how none of the elements have a className or style prop. Using className or style props at this level could be considered a code smell.

http://jxnblk.com/writing/posts/patterns-for-style-composition-in-react/

I think we can reconsider style attribute later, if we will need it.

@steida
Copy link
Author

steida commented Aug 19, 2016

Btw, I asked Sebastian Markbåge about that and he promised to respond after a weekend vacation.

@AlessandroCorradini
Copy link

AlessandroCorradini commented Aug 30, 2016

@ericf You could detect if is react-native or not like so:
https://github.com/erikras/redux-form/blob/master/src/isReactNative.js

if is react-native, set the "defaultComponent" to <Text>, else to <span>.

@jrylan
Copy link

jrylan commented Aug 30, 2016

@AlessandroCorradini that's a decent approach, but we still end up with the issue of needing to specify the use of <text> within an SVG element. <span> does not work within an SVG.

@AlessandroCorradini
Copy link

<Text> is the react-native component, it doesn't need a SVG element

@jrylan
Copy link

jrylan commented Aug 30, 2016

@AlessandroCorradini <text> (lowercase t) is for SVG:
https://developer.mozilla.org/en-US/docs/Web/SVG/Element/text

<Text> (uppercase T) is for react-native.

@AlessandroCorradini
Copy link

It's my mistake sorry :D I was in a hurry to write. I meant Text component.

@AlessandroCorradini
Copy link

I thought..my approach need dependency with react-native and this isn't good for react (not react-native) users.
Instead, you could add a component prop (not required). If it is provided, render this component like so, else render a regular span:

<Component {...this.props}>{this.props.value}</Component>
I don't know the exact prop than contains the translated value, this.props.value is "placeholder"

@jrylan
Copy link

jrylan commented Aug 30, 2016

@AlessandroCorradini I don't believe the prop idea is a good approach, because if you intend to create universal apps (using something like react-native-web), you would need to specify the prop every single time you used a react-intl component. It's really best to define the text element to use at the IntlProvider level.

The approach that @steida outlined in the first post is the perfect solution, and can easily be adjusted to accommodate SVGs as well, you would just wrap an SVG in another instance of IntlProvider, with textElement='text' or something along those lines.

@AlessandroCorradini
Copy link

AlessandroCorradini commented Aug 30, 2016

I'm agree with you. Now I'm using this custom component to use this library into react-native. It's display a warning but works:

C:\testApp\node_modules\react-native\Libraries\JavaScriptAppEngine\Initialization\ExceptionsM…:76Warning: Failed prop type: Invalid proptagNameof typefunctionsupplied toFormattedMessage, expectedstring.

TranslateText.js (Component)

'use strict';

import React from 'react';
import {Text} from 'react-native';
import {FormattedMessage} from 'react-intl';

class TranslateText extends React.Component {
    render() {
        return(
            <FormattedMessage tagName={Text} {...this.props} />
        )
    }
}

export default TranslateText;

screenshot_20160830-215806

Terms.js (Route)

'use strict';

import React from 'react';
import {Text, View} from 'react-native';
import Container from '../../components/Container';
import TranslateText from '../../components/TranslateText';

class TermsPage extends React.Component {
  render() {
    return (
        <Container>
          <TranslateText id="hello" defaultMessage="hello"/>
          </Container>
    );
  }
}



export default TermsPage;

@steida
Copy link
Author

steida commented Aug 30, 2016

@AlessandroCorradini Remember that browser code can import anything from Native and vice versa. And no, require isn't a solution because dependencies must be statically analyzable.

@mschipperheyn
Copy link
Contributor

+1 @steida

@mschipperheyn
Copy link
Contributor

To augment my +1: it's preferable to NOT detect RN vs ReactJS and automatically decide on the tag to use. RN Docs state that Text formatting is not passed through the tree like in HTML/css and recommends using a customized Text component to guarantee your fonts etc are correct. So, it might be preferable to create AText component that renders the Text with your font preferences, in which case you want AText to be the rendering component for react-intl.

@mschipperheyn
Copy link
Contributor

Any ETA on this one? Is it on the radar or one of those "maybe, if we find some spare time, but probably not"

@antoinerousseau
Copy link

You can already use it very easily in React Native, as explained in #119 (comment)

@ericf
Copy link
Collaborator

ericf commented Nov 8, 2016

@brentvatne React Fiber should allow a component's render() method to return a string, not sure how React Native will handle this, but it would be ideal for React Intl to use.

@mschipperheyn
Copy link
Contributor

I wonder why we're veering of into conceptual idea territory when the initial post in this thread offers a perfect solution.

@ericf
Copy link
Collaborator

ericf commented Nov 15, 2016

@mschipperheyn if you're eager to get the short-term solution in, would you mind opening a PR for it?

@mschipperheyn
Copy link
Contributor

Hi @ericf , I don't have a lot of time but I'll give it a go and see where I end up

@mschipperheyn
Copy link
Contributor

mschipperheyn commented Nov 16, 2016

Ok, have a look and tell me what you think: https://github.com/mschipperheyn/react-intl
It would still need some tests for react-native. But I made the changes and updated the README. I'm not sure yet if everything will work on React-Native, but I just want some feedback to hear if this is the right track

@ericf
Copy link
Collaborator

ericf commented Nov 16, 2016

@mschipperheyn can you open a PR, even if it's a WIP one?

@mschipperheyn
Copy link
Contributor

mschipperheyn commented Nov 16, 2016

#739

@mschipperheyn
Copy link
Contributor

Can someone help me test this? Should I deploy as tmp on npm to facilitate?

@mschipperheyn
Copy link
Contributor

I haven't had the time to test this in RN yet and write specific tests for it yet, (I prob will have time over the holidays) but since the changes make the react-intl more generically applicable (not depending on span), without requiring code changes, would it be better if I remove the React Native specific documentation updates, so it can be merged and as such can receive some testing in the wild for RN?

@mschipperheyn
Copy link
Contributor

mschipperheyn commented Dec 14, 2016

Ok, so I removed the react-native references from the pull request. My hope is that this makes react-intl usable in React-Native without advertising as such and hopefully generate some useful input from testing in the wild. Also, I hope this will make this merge request acceptable to be applied now instead of later.

Basically, the pull request is now "just" a change that eliminates the dependency on 'span' and makes the tag used to encompass the text configurable by specifying a textComponent attribute on the provider tag which defaults to span but can also be set as textComponent={Text}.

If there are any documentation updates necessary to facilitate the acceptance of this merge request, I'd be happy to make them.

@mschipperheyn
Copy link
Contributor

@ericf can you give me feedback, please? Would love to see this implemented

@ericf ericf closed this as completed Dec 22, 2016
@ericf
Copy link
Collaborator

ericf commented Dec 23, 2016

This is now in react-intl@2.2.0 🎉
https://github.com/yahoo/react-intl/releases/tag/v2.2.0

@ericf
Copy link
Collaborator

ericf commented Dec 23, 2016

I added a note about <IntlProvider textComponent> on the Wiki:
https://github.com/yahoo/react-intl/wiki/Components#intlprovider

It would be great if someone wanted to add more comprehensive docs to the Wiki about using with React Native and even including an example app in the repo at /examples ❤️

@mschipperheyn
Copy link
Contributor

I already have this ready. I just removed it from the deploy to expedite its release. I will add some stuff

@steida
Copy link
Author

steida commented Dec 29, 2016

As a creator of this issue, I changed my mind now. Now I think injectIntl should be used everywhere. It's nice with flowtype checking and auto-complete and definitely less verbose. <FormatWhatever seems to be the unnecessary abstraction for me. Feel free to correct me.

@ericf
Copy link
Collaborator

ericf commented Dec 29, 2016

<FormatWhatever seems to be the unnecessary abstraction for me. Feel free to correct me.

@steida React Intl's components provide an optimization for re-renders, and a component like <FormattedRelative> does auto-ticking, and <FormattedMessage> supports rich-text formatting — and this feature is about to be dramatically improved: #513 (comment)

steida added a commit to este/este that referenced this issue Dec 30, 2016
steida added a commit to este/este that referenced this issue Jan 1, 2017
* Rename some variables

* Update flow-typed

* Progress

* Header, Toolbar

* goodness

- typed style hoc ftw
- note about circular dependencies
- refactoring

* Fela 0.4

* Fix link for Fela 0.4

* Improve Text.js

* OK, I was dumb.

* Improve comment

* Progress...

* Add open-color

* progress

Need to update to flow 0.35 to continue, because invariants.

* Ups

* Hooray, thinks are getting shapes

- fontSizes and sizes, good to remember
- values are reused
- <Style /> pattern
- etc.

* Exact object types, something like immutablejs records

Remove unused APP_STORAGE_LOADED action.

* Wow, this is it. Exact types with $Keys<T> utility type ftw.

- Exact type restricts allowed props, which is the must for good DX.
- With $Keys<T>, we can extract keys from any type.
- Autocomplete doesn’t work with the {[key: Key]: Bla }, but we don’t
need that anymore with exact object type.

https://flowtype.org/docs/objects.html#exact-object-types

* OK, exact type is not ready yet. Use Exact type instead.

- Native exact type doesn’t work with spread nor intersection yet,
fortunately we can replace it with custom Exact type.
- For Theme, we can’t use native exact type nor Exact type, because the
first doesn't support spread nor intersection and the second doesn’t
support autocomplete.
- For app state, I decided to use Exact anyway, since strictness is
more important then autocomplete here.
- For Style, I decided to use plain object checking, since we can’t
detect custom Fela strings anyway.
- Note pattern, plain type A, in export Exact<A>.

Why all of that? The simple reason. We want to detect misspelled
component props. I we are there :-)

I believe this is the best trade-off we can have for now. Of course,
there is always room for more strictness.

* Box (not finished, but working). Cleaning here and there.

* Ook, we have text color.

I decided to not allow any open color in color property. Semantic
colors should be good enough. Anyone can add new semantic key, or read
from theme.colors.open directly in custom components.

Tie your hands to free your mind!

* Refactor Toolbar to Header

It’s a place specific component.

* Clean Footer, add semantic tag

* Add Paragraph

* Allow typed style prop on Box and Text

* Add box backgroundColor and border

* Remove unimportant implementation details.

Yes. H1, H2, P, OL, UL, etc. is just garbage. Not existing in RN
anyway. We don’t need it. But we should add accessibility metas, of
course.

* Improve Box border

* Add PageHeader and Heading

* Add display to Text

* Adjust themes

* Add Image component

* Simplifying API again

Flow inference ftw.

* OMG yes, finally working type checking.

* $spread instead of ...Foo.style

Because …Foo.style() breaks flow check. Also, it’s handy.

* progress

* Rename style to styled, because potential <Style> clash.

* Add back Footer and HomePage

* Ok, this is it.

Box => Text => Heading
Box => Container => Panel

* $spread to $extends, it's more familiar.

* textAlign and lineHeight belong to Text

Add some comments here and there

* Add Heading to the theme, chore

* Improve Image, fix eslint.

* Ad basic flex to Box. Check App.js pattern how to compose Box.

* Flex and chore

* This is a good pattern.

* Collocate props with components

* theme.text, leverage defaultProps

* Allow style on Box for bypassing.

* Omg omg omg

* Omg, this is omg. Automatic Vertical rhythm test.

* Omg setFontSizeAndRhythmLineHeight

* Extract createTypography and chore

* Chore

* Add superSmall, uses Boxes instead of low level css.

I wish I had a better naming

* naming is hard

* Make Container reusable

* progress

* Fela "faster than styletron" 4.1.0

* Ok, I don't like const Style = ..., collocating ftw.

* Refactor Text instead of writing explaining comments.

* Chore

* progress

- Remove lineHeight tuning from Text, I was wrong. It would destroy
multiline texts. We need a better approach.
- Box (and text) border must enforce and adjust vertical padding, there
is no other way how to compensate rhythm without additional elements.
- Improve typography size granularity. Like with monochord, tones must
be created by halving. Octave ftw.

* Fix rhythm for any border. Add friendly dev warning. Add steps for greater granularity.

This is dope shit.

* Fix Heading, Padding, add future button example.

Plus some fixes here and there.

* Improve rhythm warning, allow to suppress it via noRhythm

* Ensure vertical rhythm for images

* Hmm, consider Size unit for borderRadius and borderWidth as well.

* Symmetric steps

* Proximity

* progress

- rename createTheme to configureTheme
- Box: use sizes for vertical paddings and margins, and fontSizes for
horizontal paddings and margins
- reverse typography sizes order, start with the smallest
- port fxbml hoc
- add Button , not finished yet

* progress

* progress

* Added onClick prop to button and fixed justifyContent prop in Box (#1269)

* chore

* improve homepage example

* Clean BoxProps, type missing prop

* Box widths and heights are RhythmOrString as well

* Pattern to put space between child

Render them as an array and use marginLeft with i && foo

* Button, via getPlatformType it's div with tabIndex na role.

* Ups

* Remove info, only primary, success, warning, danger make sense.

* Fix prefixed style types, sort them, add text antialiasing

http://usabilitypost.com/2012/11/05/stop-fixing-font-smoothing/

tldr; It’s great, but only for small text with background. Facebook
uses it too.

* Text antialiasing

It fixes Chrome and Firefox on macOS. Edge hasn’t such setting.

* Add disabled button

* progress

- fix eslint
- add user-select for themes
- disabled button, opacity from theme and tabIndex -1
- chore

* chore

* improve system font

* This

Until new flow, we have to type defaultProps manually.

* Ok, defaultProps are ok, remove heading bold

* Progress

* Refactor styled, fix $map.

* Fix Box compensate padding

* Increase PageHeader Heading size

* progress

- outline sucks, it’s hard to implement and ugly as well, iOS and
medium.com use coloured buttons instead of outlines. Este likes it.
- some fixes here and there
- improve app header look

* Switch theme

* Add ToggleBaseline component, add userSelect none to Button

* redux-connect 5

* Nice pattern

We need ugly blue borders, but with key we can remove them after click
via key. Very nice pattern.

* Ok, it was pretty stupid idea.

* Space on div button dispatches click

https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Tec
hniques/Using_the_button_role

* Chore

* Fix eslint and update deps

* Fix Image rhythm size

* Loading component

* UsersPage

- remove react-gravatar, use getUserPhotoUrl
- update deps (so fast with yarn)
- some styling here and there
- fixes

* Ok, make baseline helper lighter

* Tie your hands, free your mind.

- em, rem, px, aren’t universal and isolated
- having ability to specify em on the box and on the child with another
size could lead to nasty inconsistencies
- number is like rem, but based on the baseline

* Flexbox ftw

I just fixed weird vertical space with setting display to flex. It
seems that flex should be new a new block. Let’s be explicit for a
while, then rethink it.

* Update deps

* Increase timeout, because life sucks.

* Fok deps

* Yarn 0.18.1 and updated flow-typed

* PageHeader description optional

* Update deps

* Form component

* Input component stub

* NewTodo wip

* Fix some eslint errrors

* wip

* Ok, StyledFoo is the pattern.

* Update deps

* Update static global browser styles

We need that for fixing stuff.

* Refactor Color types, to get ColorProps for Button primary etc. Also, improve native fontFamily.

* Ok, render Button as button for browser. We don't need mapping to div.

* This is awesome. We don't need foking defaultProps.

The problem I have with defaultProps is, that we can’t read from theme,
which sucks socks. With destructuring and default arguments, we don’t
need that shit.

* wip

Going to have a better button api.

* Rename type $Exact to $Strict and explain it.

Remove comment about callable objects, because we don’t need
defaultProps anymore.

* Disable eslint react/prop-types, can't detect flow correctly

* Clean styled.js

* We don't need that anymore.

* Improve $extends

I wish spread work with flow. Nevermind, this is good enough.

* Ok, render button as div again.

Render div because button is not consistently rendered across browsers.
Looking to you bloody Firefox.

* OK, this is it.

- Any Text component can have colorProp like primary etc.

* Update deps

* Chore

* Add verticalAlign to Box

* Refactor Box border to separate color

* Enable remoteHotReload by default

* Add tiny color helper library

* Input wip

* Button wip

* Remove unnecessary type annotation

* Readability

* Aka secondary

* wip

* Improve fontSmoothing fix

* Fix small Button

* Fix Text color bug

* Active Button state

* Move state.themes to state.app where it belongs

* Comment

* Ratios suck

* theme.block.maxWidth

* Persist app baselineShown

* Finish Input, this is good

* Wip

* Update deps and flow-typed

* /todos done

* Rename /* @flow */ to // @flow

* OK, never import whole ramda.

* OK, FormattedWhatever sucks. Favour injectIntl

- injectIntl is reduces boilerplate
- it’s already universal
- never ever think about what should be user, component or not?
- not sure whether React fiber will solve it

* The Label

* wip

* Small tip

* Rewrite Input component

- multiline
- super minimal
- error

* Remove webkit resizer entirely

* wip

* Ok, use FormattedXY components.

formatjs/formatjs#600 (comment)

* FieldsPage wip

Add field prop to Input. Why? It looks nicer sure, but also JSX spread
breaks flowtype detection.

* IntlPage wip

* IntlPage

* Ramda 0.23 and other deps

* Add OfflinePage with Pre component

* Add iflow-react-intl, remove Intl type

* NotFoundPage

* Move SwitchTheme where it belongs

* MePage

* Reenable no-class-assign, we don't need it with ramda compose

* Use field prop

We need that because {…for} breaks flow type checking.

* Improve Loading, it's text so it's fully syllable

* Add disabled state to Input

* Port focus HOC helper

* Add ugly hack for Form

* Almost done SignInPage

Need to add SignInError

* Add Message component

There is a pattern, just Text component with default values.

* Flowtype ValidationError

I still think that flow typed monad should be better.

* Finish SignInPage

* Restrict input only for text based fields

With text base design, placeholder is required.

* FieldsPage wip

* Remove old UI, finally.

* Fix eslint

* This is default now, no need to have it in _config stub

* Clean messages

* fok
@ghost
Copy link

ghost commented Jan 12, 2017

For me, I worked around the issue by calling the formatMessage function which returns just the string, no html tags like FormattedMessage does. Here's an example:

// Add intl to contextTypes, so it can be access with this.intl
MyComponentName.contextTypes = {
  intl: PropTypes.object.isRequired,
};

// Inside my compontent
class MyComponentName extends React.PureComponent {
  render() {
    <Text>{ this.context.intl.formatMessage({ ...messages.home }) }</Text>
  }
}

The object passed into formatMessage is the same that you would pass into FormattedMessage

<FormattedMessage {...messages.home } />

@steida
Copy link
Author

steida commented Jun 24, 2017

@steida React Intl's components provide an optimization for re-renders, and a component like does auto-ticking, and supports rich-text formatting — and this feature is about to be dramatically improved: #513 (comment)

I see your points, still. An optimization for re-renders is nice, but it's task for my view component I suppose. Yep, FormattedRelative does sense. FormattedMessage will not work for React Native I guess, feel free to correct me.

The reason why I prefer (maybe I am wrong) intl is flow typing. I would love to have typed messages.
See:

<FormattedMessage
  defaultMessage="Starter kit for universal apps."
  id="app.description"
/>

How to detect missing message id? It's possible, but it would require a lot of boilerplate I guess.

Also, check flow-typed/flow-typed#981

@39otrebla
Copy link

It seems FormattedMessage does not support other react-native components as values. For example, the following code produces only Hello, everything after the first { gets lost:

const messages = {
  "HelloAll": "Hello{all}!"
};

[...]

const allText = <Text>, world</Text>;

[...]

render() {
  return <FormattedMessage id="HelloAll" values={{ all: allText }} />;
}

It's quite annoying since we have tons of custom Text components to highlight text around the app.

Does anyone know if there's another way to achieve this in react-native?

EDIT
intl.formatMessage() doesn't work either, it would print: Hello[object Object]!.

@longlho
Copy link
Member

longlho commented Aug 14, 2019

@39otrebla can u create a separate issue for tracking? This sounds like a bug.

@39otrebla
Copy link

I'm not sure this is a bug, react-intl is not explicitly developed for react-native.. isn't it? Indeed, it seems that FormattedMessage doesn't recognize native tags because they are objects rather than strings, as well as formatMessage() (indeed, the latter returns Hello[object Object]! as native tags most likely do not implement toString()).

It sounds more like a feature request to me. Let me know.

@longlho
Copy link
Member

longlho commented Aug 14, 2019

We do support passing arbitrary objects in (there's no explicit check if it's a React component or anything) so this is a bug to me.

Are you using latest react-intl version btw?

@antoinerousseau
Copy link

antoinerousseau commented Aug 14, 2019

@39otrebla React Native is supported, so it looks like a bug (if you are using a recent version of react-intl), because react nodes in values should work.

@39otrebla
Copy link

@antoinerousseau @longlho #1430 . Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants