diff --git a/README.md b/README.md
index aac20768..f6496a97 100644
--- a/README.md
+++ b/README.md
@@ -115,6 +115,7 @@ Exported modules:
* [`AppState`](docs/apis/AppState.md)
* [`AsyncStorage`](docs/apis/AsyncStorage.md)
* [`Dimensions`](docs/apis/Dimensions.md)
+ * [`I18nManager`](docs/apis/I18nManager.md)
* [`NativeMethods`](docs/apis/NativeMethods.md)
* [`NetInfo`](docs/apis/NetInfo.md)
* [`PanResponder`](http://facebook.github.io/react-native/releases/0.20/docs/panresponder.html#content) (mirrors React Native)
diff --git a/docs/apis/I18nManager.md b/docs/apis/I18nManager.md
new file mode 100644
index 00000000..9258bda6
--- /dev/null
+++ b/docs/apis/I18nManager.md
@@ -0,0 +1,27 @@
+# I18nManager
+
+Control and set the layout and writing direction of the application. You must
+set `dir="rtl"` (and should set `lang="${lang}"`) on the root element of your
+app.
+
+## Properties
+
+**isRTL**: bool = false
+
+Whether the application is currently in RTL mode.
+
+## Methods
+
+static **allowRTL**(allowRTL: bool)
+
+Allow the application to display in RTL mode.
+
+static **forceRTL**(allowRTL: bool)
+
+Force the application to display in RTL mode.
+
+static **setRTL**(allowRTL: bool)
+
+Set the application to display in RTL mode. You will need to determine the
+user's preferred locale and if it is an RTL language. (This is best done on the
+server as it is notoriously inaccurate to deduce client-side.)
diff --git a/docs/apis/NetInfo.md b/docs/apis/NetInfo.md
index 7a8655ab..a2fdf7f4 100644
--- a/docs/apis/NetInfo.md
+++ b/docs/apis/NetInfo.md
@@ -29,7 +29,7 @@ static **removeEventListener**(eventName: ChangeEventName, handler: Function)
## Properties
-**isConnected**
+**isConnected**: bool = true
Available on all user agents. Asynchronously fetch a boolean to determine
internet connectivity.
diff --git a/docs/components/Text.md b/docs/components/Text.md
index 13ae37a8..06cd3631 100644
--- a/docs/components/Text.md
+++ b/docs/components/Text.md
@@ -68,14 +68,22 @@ Lets the user select the text.
+ `fontWeight`
+ `letterSpacing`
+ `lineHeight`
-+ `textAlign`
++ `textAlign`‡
+ `textAlignVertical`
+ `textDecorationLine`
-+ `textShadow`
++ `textOverflow`
++ `textRendering`
++ `textShadowColor`
++ `textShadowOffset`‡
++ `textShadowRadius`
+ `textTransform`
++ `unicodeBidi`
+ `whiteSpace`
+ `wordWrap`
-+ `writingDirection`
++ `writingDirection`‡
+
+‡ This property can be suffixed with `$noI18n` to prevent automatic
+bidi-flipping in RTL mode. This is only supported if `Platform.OS === 'web'`.
**testID**: string
diff --git a/docs/components/View.md b/docs/components/View.md
index c5120fa2..3bbdaf89 100644
--- a/docs/components/View.md
+++ b/docs/components/View.md
@@ -108,10 +108,26 @@ from `style`.
+ `backgroundPosition`
+ `backgroundRepeat`
+ `backgroundSize`
-+ `borderColor`
-+ `borderRadius`
-+ `borderStyle`
-+ `borderWidth`
++ `borderColor` (single value)
++ `borderTopColor`
++ `borderBottomColor`
++ `borderRightColor`‡
++ `borderLeftColor`‡
++ `borderRadius` (single value)
++ `borderTopLeftRadius`‡
++ `borderTopRightRadius`‡
++ `borderBottomLeftRadius`‡
++ `borderBottomRightRadius`‡
++ `borderStyle` (single value)
++ `borderTopStyle`
++ `borderRightStyle`‡
++ `borderBottomStyle`
++ `borderLeftStyle`‡
++ `borderWidth` (single value)
++ `borderBottomWidth`
++ `borderLeftWidth`‡
++ `borderRightWidth`‡
++ `borderTopWidth`
+ `bottom`
+ `boxShadow`
+ `boxSizing`
@@ -124,12 +140,12 @@ from `style`.
+ `flexWrap`
+ `height`
+ `justifyContent`
-+ `left`
++ `left`‡
+ `margin` (single value)
+ `marginBottom`
+ `marginHorizontal`
-+ `marginLeft`
-+ `marginRight`
++ `marginLeft`‡
++ `marginRight`‡
+ `marginTop`
+ `marginVertical`
+ `maxHeight`
@@ -144,12 +160,12 @@ from `style`.
+ `padding` (single value)
+ `paddingBottom`
+ `paddingHorizontal`
-+ `paddingLeft`
-+ `paddingRight`
++ `paddingLeft`‡
++ `paddingRight`‡
+ `paddingTop`
+ `paddingVertical`
+ `position`
-+ `right`
++ `right`‡
+ `top`
+ `transform`
+ `transformMatrix`
@@ -158,6 +174,9 @@ from `style`.
+ `width`
+ `zIndex`
+‡ This property can be suffixed with `$noI18n` to prevent automatic
+bidi-flipping in RTL mode. This is only supported if `Platform.OS === 'web'`.
+
Default:
```js
diff --git a/examples/Text/TextExample.js b/examples/Text/TextExample.js
index 1f88736f..f6f41e80 100644
--- a/examples/Text/TextExample.js
+++ b/examples/Text/TextExample.js
@@ -271,7 +271,7 @@ const examples = [
auto (default) - english LTR
-
+
أحب اللغة العربية auto (default) - arabic RTL
diff --git a/src/apis/I18nManager/__tests__/index-test.js b/src/apis/I18nManager/__tests__/index-test.js
new file mode 100644
index 00000000..f2de7590
--- /dev/null
+++ b/src/apis/I18nManager/__tests__/index-test.js
@@ -0,0 +1,38 @@
+/* eslint-env mocha */
+
+import assert from 'assert'
+import I18nManager from '..'
+
+suite('apis/I18nManager', () => {
+ suite('when RTL not enabled', () => {
+ setup(() => {
+ I18nManager.setRTL(false)
+ })
+
+ test('is "false" by default', () => {
+ assert.equal(I18nManager.isRTL, false)
+ })
+
+ test('is "true" when forced', () => {
+ I18nManager.forceRTL(true)
+ assert.equal(I18nManager.isRTL, true)
+ I18nManager.forceRTL(false)
+ })
+ })
+
+ suite('when RTL is enabled', () => {
+ setup(() => {
+ I18nManager.setRTL(true)
+ })
+
+ test('is "true" by default', () => {
+ assert.equal(I18nManager.isRTL, true)
+ })
+
+ test('is "false" when not allowed', () => {
+ I18nManager.allowRTL(false)
+ assert.equal(I18nManager.isRTL, false)
+ I18nManager.allowRTL(true)
+ })
+ })
+})
diff --git a/src/apis/I18nManager/index.js b/src/apis/I18nManager/index.js
new file mode 100644
index 00000000..f454c34b
--- /dev/null
+++ b/src/apis/I18nManager/index.js
@@ -0,0 +1,33 @@
+type I18nManagerStatus = {
+ allowRTL: (allowRTL: boolean) => {},
+ forceRTL: (forceRTL: boolean) => {},
+ setRTL: (setRTL: boolean) => {},
+ isRTL: boolean
+}
+
+let isApplicationLanguageRTL = false
+let isRTLAllowed = true
+let isRTLForced = false
+
+const I18nManager: I18nManagerStatus = {
+ allowRTL(bool) {
+ isRTLAllowed = bool
+ },
+ forceRTL(bool) {
+ isRTLForced = bool
+ },
+ setRTL(bool) {
+ isApplicationLanguageRTL = bool
+ },
+ get isRTL() {
+ if (isRTLForced) {
+ return true
+ }
+ if (isRTLAllowed && isApplicationLanguageRTL) {
+ return true
+ }
+ return false
+ }
+}
+
+module.exports = I18nManager
diff --git a/src/apis/StyleSheet/StyleSheetValidation.js b/src/apis/StyleSheet/StyleSheetValidation.js
index 307ad574..58dd317f 100644
--- a/src/apis/StyleSheet/StyleSheetValidation.js
+++ b/src/apis/StyleSheet/StyleSheetValidation.js
@@ -61,7 +61,6 @@ StyleSheetValidation.addValidStylePropTypes({
clear: PropTypes.string,
cursor: PropTypes.string,
display: PropTypes.string,
- direction: PropTypes.string, /* @private */
float: PropTypes.oneOf([ 'left', 'none', 'right' ]),
font: PropTypes.string, /* @private */
listStyle: PropTypes.string
diff --git a/src/apis/StyleSheet/__tests__/i18nStyle-test.js b/src/apis/StyleSheet/__tests__/i18nStyle-test.js
new file mode 100644
index 00000000..058dab68
--- /dev/null
+++ b/src/apis/StyleSheet/__tests__/i18nStyle-test.js
@@ -0,0 +1,91 @@
+/* eslint-env mocha */
+
+import assert from 'assert'
+import I18nManager from '../../I18nManager'
+import i18nStyle from '../i18nStyle'
+
+const initial = {
+ borderLeftColor: 'red',
+ borderRightColor: 'blue',
+ borderTopLeftRadius: 10,
+ borderTopRightRadius: '1rem',
+ borderBottomLeftRadius: 20,
+ borderBottomRightRadius: '2rem',
+ borderLeftStyle: 'solid',
+ borderRightStyle: 'dotted',
+ borderLeftWidth: 5,
+ borderRightWidth: 6,
+ left: 1,
+ marginLeft: 7,
+ marginRight: 8,
+ paddingLeft: 9,
+ paddingRight: 10,
+ right: 2,
+ textAlign: 'left',
+ textShadowOffset: { width: '1rem', height: 10 },
+ writingDirection: 'ltr'
+}
+
+const initialNoI18n = Object.keys(initial).reduce((acc, prop) => {
+ const newProp = `${prop}$noI18n`
+ acc[newProp] = initial[prop]
+ return acc
+}, {})
+
+const expected = {
+ borderLeftColor: 'blue',
+ borderRightColor: 'red',
+ borderTopLeftRadius: '1rem',
+ borderTopRightRadius: 10,
+ borderBottomLeftRadius: '2rem',
+ borderBottomRightRadius: 20,
+ borderLeftStyle: 'dotted',
+ borderRightStyle: 'solid',
+ borderLeftWidth: 6,
+ borderRightWidth: 5,
+ left: 2,
+ marginLeft: 8,
+ marginRight: 7,
+ paddingLeft: 10,
+ paddingRight: 9,
+ right: 1,
+ textAlign: 'right',
+ textShadowOffset: { width: '-1rem', height: 10 },
+ writingDirection: 'rtl'
+}
+
+suite('apis/StyleSheet/i18nStyle', () => {
+ suite('LTR mode', () => {
+ setup(() => {
+ I18nManager.allowRTL(false)
+ })
+
+ teardown(() => {
+ I18nManager.allowRTL(true)
+ })
+
+ test('does not auto-flip', () => {
+ assert.deepEqual(i18nStyle(initial), initial)
+ })
+ test('normalizes properties', () => {
+ assert.deepEqual(i18nStyle(initialNoI18n), initial)
+ })
+ })
+
+ suite('RTL mode', () => {
+ setup(() => {
+ I18nManager.forceRTL(true)
+ })
+
+ teardown(() => {
+ I18nManager.forceRTL(false)
+ })
+
+ test('does auto-flip', () => {
+ assert.deepEqual(i18nStyle(initial), expected)
+ })
+ test('normalizes properties', () => {
+ assert.deepEqual(i18nStyle(initialNoI18n), initial)
+ })
+ })
+})
diff --git a/src/apis/StyleSheet/createReactStyleObject.js b/src/apis/StyleSheet/createReactStyleObject.js
index ce8d99b6..1657a6f6 100644
--- a/src/apis/StyleSheet/createReactStyleObject.js
+++ b/src/apis/StyleSheet/createReactStyleObject.js
@@ -1,5 +1,6 @@
import expandStyle from './expandStyle'
import flattenStyle from '../../modules/flattenStyle'
+import i18nStyle from './i18nStyle'
import processTextShadow from './processTextShadow'
import processTransform from './processTransform'
import processVendorPrefixes from './processVendorPrefixes'
@@ -10,8 +11,10 @@ const plugins = [
processVendorPrefixes
]
-const applyPlugins = (style) => plugins.reduce((style, plugin) => plugin(style), style)
+const applyPlugins = (style) => {
+ return plugins.reduce((style, plugin) => plugin(style), style)
+}
-const createReactDOMStyleObject = (reactNativeStyle) => applyPlugins(expandStyle(flattenStyle(reactNativeStyle)))
+const createReactDOMStyleObject = (reactNativeStyle) => applyPlugins(expandStyle(i18nStyle(flattenStyle(reactNativeStyle))))
module.exports = createReactDOMStyleObject
diff --git a/src/apis/StyleSheet/i18nStyle.js b/src/apis/StyleSheet/i18nStyle.js
new file mode 100644
index 00000000..3ab00fc7
--- /dev/null
+++ b/src/apis/StyleSheet/i18nStyle.js
@@ -0,0 +1,124 @@
+import I18nManager from '../I18nManager'
+
+const CSS_UNIT_RE = /^[+-]?\d*(?:\.\d+)?(?:[Ee][+-]?\d+)?(\w*)/
+
+/**
+ * Map of property names to their BiDi equivalent.
+ */
+const PROPERTIES_TO_SWAP = {
+ 'borderTopLeftRadius': 'borderTopRightRadius',
+ 'borderTopRightRadius': 'borderTopLeftRadius',
+ 'borderBottomLeftRadius': 'borderBottomRightRadius',
+ 'borderBottomRightRadius': 'borderBottomLeftRadius',
+ 'borderLeftColor': 'borderRightColor',
+ 'borderLeftStyle': 'borderRightStyle',
+ 'borderLeftWidth': 'borderRightWidth',
+ 'borderRightColor': 'borderLeftColor',
+ 'borderRightWidth': 'borderLeftWidth',
+ 'borderRightStyle': 'borderLeftStyle',
+ 'left': 'right',
+ 'marginLeft': 'marginRight',
+ 'marginRight': 'marginLeft',
+ 'paddingLeft': 'paddingRight',
+ 'paddingRight': 'paddingLeft',
+ 'right': 'left'
+}
+
+const PROPERTIES_SWAP_LEFT_RIGHT = {
+ 'clear': true,
+ 'float': true,
+ 'textAlign': true
+}
+
+const PROPERTIES_SWAP_LTR_RTL = {
+ 'writingDirection': true
+}
+
+/**
+ * Invert the sign of a numeric-like value
+ */
+const additiveInverse = (value: String | Number) => {
+ if (typeof value === 'string') {
+ const number = parseFloat(value, 10) * -1
+ const unit = getUnit(value)
+ return `${number}${unit}`
+ } else if (isNumeric(value)) {
+ return value * -1
+ }
+}
+
+/**
+ * BiDi flip the given property.
+ */
+const flipProperty = (prop:String): String => {
+ return PROPERTIES_TO_SWAP.hasOwnProperty(prop) ? PROPERTIES_TO_SWAP[prop] : prop
+}
+
+/**
+ * BiDi flip translateX
+ */
+const flipTransform = (transform: Object): Object => {
+ const translateX = transform.translateX
+ if (translateX != null) {
+ transform.translateX = additiveInverse(translateX)
+ }
+ return transform
+}
+
+/**
+ * Get the CSS unit for string values
+ */
+const getUnit = (str) => str.match(CSS_UNIT_RE)[1]
+
+const isNumeric = (n) => {
+ return !isNaN(parseFloat(n)) && isFinite(n)
+}
+
+const swapLeftRight = (value:String): String => {
+ return value === 'left' ? 'right' : value === 'right' ? 'left' : value
+}
+
+const swapLtrRtl = (value:String): String => {
+ return value === 'ltr' ? 'rtl' : value === 'rtl' ? 'ltr' : value
+}
+
+const i18nStyle = (style = {}) => {
+ const newStyle = {}
+ for (const prop in style) {
+ if (style.hasOwnProperty(prop)) {
+ const indexOfNoFlip = prop.indexOf('$noI18n')
+
+ if (I18nManager.isRTL) {
+ if (PROPERTIES_TO_SWAP[prop]) {
+ const newProp = flipProperty(prop)
+ newStyle[newProp] = style[prop]
+ } else if (PROPERTIES_SWAP_LEFT_RIGHT[prop]) {
+ newStyle[prop] = swapLeftRight(style[prop])
+ } else if (PROPERTIES_SWAP_LTR_RTL[prop]) {
+ newStyle[prop] = swapLtrRtl(style[prop])
+ } else if (prop === 'textShadowOffset') {
+ newStyle[prop] = style[prop]
+ newStyle[prop].width = additiveInverse(style[prop].width)
+ } else if (prop === 'transform') {
+ newStyle[prop] = style[prop].map(flipTransform)
+ } else if (indexOfNoFlip > -1) {
+ const newProp = prop.substring(0, indexOfNoFlip)
+ newStyle[newProp] = style[prop]
+ } else {
+ newStyle[prop] = style[prop]
+ }
+ } else {
+ if (indexOfNoFlip > -1) {
+ const newProp = prop.substring(0, indexOfNoFlip)
+ newStyle[newProp] = style[prop]
+ } else {
+ newStyle[prop] = style[prop]
+ }
+ }
+ }
+ }
+
+ return newStyle
+}
+
+module.exports = i18nStyle
diff --git a/src/components/Text/TextStylePropTypes.js b/src/components/Text/TextStylePropTypes.js
index b6c0c2f2..75631f4f 100644
--- a/src/components/Text/TextStylePropTypes.js
+++ b/src/components/Text/TextStylePropTypes.js
@@ -1,32 +1,7 @@
-import { PropTypes } from 'react'
-import ColorPropType from '../../propTypes/ColorPropType'
+import TextPropTypes from '../../propTypes/TextPropTypes'
import ViewStylePropTypes from '../View/ViewStylePropTypes'
-const { number, oneOf, oneOfType, shape, string } = PropTypes
-const numberOrString = oneOfType([ number, string ])
-
module.exports = {
...ViewStylePropTypes,
- color: ColorPropType,
- fontFamily: string,
- fontSize: numberOrString,
- fontStyle: string,
- fontWeight: string,
- letterSpacing: numberOrString,
- lineHeight: numberOrString,
- textAlign: oneOf([ 'center', 'inherit', 'justify', 'justify-all', 'left', 'right' ]),
- textAlignVertical: oneOf([ 'auto', 'bottom', 'center', 'top' ]),
- textDecorationLine: string,
- /* @platform web */
- textOverflow: string,
- textShadowColor: ColorPropType,
- textShadowOffset: shape({ width: number, height: number }),
- textShadowRadius: number,
- /* @platform web */
- textTransform: oneOf([ 'capitalize', 'lowercase', 'none', 'uppercase' ]),
- /* @platform web */
- whiteSpace: string,
- /* @platform web */
- wordWrap: string,
- writingDirection: oneOf([ 'auto', 'ltr', 'rtl' ])
+ ...TextPropTypes
}
diff --git a/src/core.js b/src/core.js
index 1100e200..8c7d1e5e 100644
--- a/src/core.js
+++ b/src/core.js
@@ -3,6 +3,7 @@ import './modules/injectResponderEventPlugin'
import findNodeHandle from './modules/findNodeHandle'
import ReactDOM from 'react-dom'
import ReactDOMServer from 'react-dom/server'
+import I18nManager from './apis/I18nManager'
import StyleSheet from './apis/StyleSheet'
import Image from './components/Image'
import Text from './components/Text'
@@ -15,6 +16,7 @@ const ReactNativeCore = {
renderToStaticMarkup: ReactDOMServer.renderToStaticMarkup,
renderToString: ReactDOMServer.renderToString,
unmountComponentAtNode: ReactDOM.unmountComponentAtNode,
+ I18nManager,
StyleSheet,
Image,
Text,
diff --git a/src/index.js b/src/index.js
index 27ece9dc..8155ca92 100644
--- a/src/index.js
+++ b/src/index.js
@@ -11,6 +11,7 @@ import AppState from './apis/AppState'
import AsyncStorage from './apis/AsyncStorage'
import Dimensions from './apis/Dimensions'
import Easing from 'animated/lib/Easing'
+import I18nManager from './apis/I18nManager'
import InteractionManager from './apis/InteractionManager'
import NetInfo from './apis/NetInfo'
import PanResponder from './apis/PanResponder'
@@ -59,6 +60,7 @@ const ReactNative = {
AsyncStorage,
Dimensions,
Easing,
+ I18nManager,
InteractionManager,
NetInfo,
PanResponder,
diff --git a/src/propTypes/BorderPropTypes.js b/src/propTypes/BorderPropTypes.js
index 238cc1e5..8d99a5d7 100644
--- a/src/propTypes/BorderPropTypes.js
+++ b/src/propTypes/BorderPropTypes.js
@@ -19,7 +19,16 @@ const BorderPropTypes = {
borderTopStyle: BorderStylePropType,
borderRightStyle: BorderStylePropType,
borderBottomStyle: BorderStylePropType,
- borderLeftStyle: BorderStylePropType
+ borderLeftStyle: BorderStylePropType,
+ /* Props to opt-out of RTL flipping */
+ borderLeftColor$noI18n: ColorPropType,
+ borderRightColor$noI18n: ColorPropType,
+ borderTopLeftRadius$noI18n: numberOrString,
+ borderTopRightRadius$noI18n: numberOrString,
+ borderBottomLeftRadius$noI18n: numberOrString,
+ borderBottomRightRadius$noI18n: numberOrString,
+ borderLeftStyle$noI18n: BorderStylePropType,
+ borderRightStyle$noI18n: BorderStylePropType
}
module.exports = BorderPropTypes
diff --git a/src/propTypes/LayoutPropTypes.js b/src/propTypes/LayoutPropTypes.js
index d83f2d09..5f46ed53 100644
--- a/src/propTypes/LayoutPropTypes.js
+++ b/src/propTypes/LayoutPropTypes.js
@@ -48,7 +48,16 @@ const LayoutPropTypes = {
left: numberOrString,
position: oneOf([ 'absolute', 'fixed', 'relative', 'static' ]),
right: numberOrString,
- top: numberOrString
+ top: numberOrString,
+ // opt-out of RTL flipping
+ borderLeftWidth$noI18n: numberOrString,
+ borderRightWidth$noI18n: numberOrString,
+ left$noI18n: numberOrString,
+ marginLeft$noI18n: numberOrString,
+ marginRight$noI18n: numberOrString,
+ paddingLeft$noI18n: numberOrString,
+ paddingRight$noI18n: numberOrString,
+ right$noI18n: numberOrString
}
module.exports = LayoutPropTypes
diff --git a/src/propTypes/TextPropTypes.js b/src/propTypes/TextPropTypes.js
new file mode 100644
index 00000000..8bc969ee
--- /dev/null
+++ b/src/propTypes/TextPropTypes.js
@@ -0,0 +1,45 @@
+import ColorPropType from './ColorPropType'
+import { PropTypes } from 'react'
+
+const { number, oneOf, oneOfType, shape, string } = PropTypes
+const numberOrString = oneOfType([ number, string ])
+
+const ShadowOffsetPropType = shape({ width: number, height: number })
+const TextAlignPropType = oneOf([ 'center', 'inherit', 'justify', 'justify-all', 'left', 'right' ])
+const WritingDirectionPropType = oneOf([ 'auto', 'ltr', 'rtl' ])
+
+const TextPropTypes = {
+ // box model
+ color: ColorPropType,
+ fontFamily: string,
+ fontSize: numberOrString,
+ fontStyle: string,
+ fontWeight: string,
+ letterSpacing: numberOrString,
+ lineHeight: numberOrString,
+ textAlign: TextAlignPropType,
+ textAlignVertical: oneOf([ 'auto', 'bottom', 'center', 'top' ]),
+ textDecorationLine: string,
+ /* @platform web */
+ textOverflow: string,
+ /* @platform web */
+ textRendering: oneOf([ 'auto', 'geometricPrecision', 'optimizeLegibility', 'optimizeSpeed' ]),
+ textShadowColor: ColorPropType,
+ textShadowOffset: ShadowOffsetPropType,
+ textShadowRadius: number,
+ /* @platform web */
+ textTransform: oneOf([ 'capitalize', 'lowercase', 'none', 'uppercase' ]),
+ /* @platform web */
+ unicodeBidi: oneOf([ 'normal', 'bidi-override', 'embed', 'isolate', 'isolate-override', 'plaintext' ]),
+ /* @platform web */
+ whiteSpace: string,
+ /* @platform web */
+ wordWrap: string,
+ writingDirection: WritingDirectionPropType,
+ // opt-out of RTL flipping
+ textAlign$noI18n: TextAlignPropType,
+ textShadowOffset$noI18n: ShadowOffsetPropType,
+ writingDirection$noI18n: WritingDirectionPropType
+}
+
+module.exports = TextPropTypes