diff --git a/packages/i18n/CHANGELOG.md b/packages/i18n/CHANGELOG.md
index 8eb9757eb2088..700b3b520eefb 100644
--- a/packages/i18n/CHANGELOG.md
+++ b/packages/i18n/CHANGELOG.md
@@ -1,3 +1,9 @@
+## Master
+
+### New Feature
+
+- Add `isRTL` function (#20298)
+
## 3.1.0 (2018-11-15)
### Enhancements
diff --git a/packages/i18n/README.md b/packages/i18n/README.md
index 50376d53c3647..21847b5f3f017 100644
--- a/packages/i18n/README.md
+++ b/packages/i18n/README.md
@@ -27,6 +27,19 @@ For a complete example, see the [Internationalization section of the Block Edito
+# **isRTL**
+
+Check if current locale is RTL.
+
+**RTL (Right To Left)** is a locale property indicating that text is written from right to left.
+For example, the `he` locale (for Hebrew) specifies right-to-left. Arabic (ar) is another common
+language written RTL. The opposite of RTL, LTR (Left To Right) is used in other languages,
+including English (`en`, `en-US`, `en-GB`, etc.), Spanish (`es`), and French (`fr`).
+
+_Returns_
+
+- `boolean`: Whether locale is RTL.
+
# **setLocaleData**
Merges locale data into the Tannin instance by domain. Accepts data in a
diff --git a/packages/i18n/src/index.js b/packages/i18n/src/index.js
index c696cb9f76400..2b4286819c9ca 100644
--- a/packages/i18n/src/index.js
+++ b/packages/i18n/src/index.js
@@ -150,6 +150,20 @@ export function _nx( single, plural, number, context, domain ) {
return dcnpgettext( domain, context, single, plural, number );
}
+/**
+ * Check if current locale is RTL.
+ *
+ * **RTL (Right To Left)** is a locale property indicating that text is written from right to left.
+ * For example, the `he` locale (for Hebrew) specifies right-to-left. Arabic (ar) is another common
+ * language written RTL. The opposite of RTL, LTR (Left To Right) is used in other languages,
+ * including English (`en`, `en-US`, `en-GB`, etc.), Spanish (`es`), and French (`fr`).
+ *
+ * @return {boolean} Whether locale is RTL.
+ */
+export function isRTL() {
+ return 'rtl' === _x( 'ltr', 'text direction' );
+}
+
/**
* Returns a formatted string. If an error occurs in applying the format, the
* original format string is returned.
diff --git a/packages/i18n/src/test/index.js b/packages/i18n/src/test/index.js
index b5e68537754df..5246bc8f3659b 100644
--- a/packages/i18n/src/test/index.js
+++ b/packages/i18n/src/test/index.js
@@ -1,8 +1,3 @@
-/**
- * Internal dependencies
- */
-import { sprintf, __, _x, _n, _nx, setLocaleData } from '../';
-
// Mock memoization as identity function. Inline since Jest errors on out-of-
// scope references in a mock callback.
jest.mock( 'memize', () => ( fn ) => fn );
@@ -31,22 +26,34 @@ const additionalLocaleData = {
'%d cat': [ '%d chat', '%d chats' ],
};
-setLocaleData( localeData, 'test_domain' );
+// Get clean locale data
+let sprintf, __, _x, _n, _nx, isRTL, setLocaleData;
+beforeEach( () => {
+ const module = require.resolve( '..' );
+ delete require.cache[ module ];
+ ( { sprintf, __, _x, _n, _nx, isRTL, setLocaleData } = require( '..' ) );
+} );
describe( 'i18n', () => {
describe( '__', () => {
+ beforeEach( setDefaultLocalData );
+
it( 'use the translation', () => {
expect( __( 'hello', 'test_domain' ) ).toBe( 'bonjour' );
} );
} );
describe( '_x', () => {
+ beforeEach( setDefaultLocalData );
+
it( 'use the translation with context', () => {
expect( _x( 'feed', 'verb', 'test_domain' ) ).toBe( 'nourrir' );
} );
} );
describe( '_n', () => {
+ beforeEach( setDefaultLocalData );
+
it( 'use the plural form', () => {
expect( _n( '%d banana', '%d bananas', 3, 'test_domain' ) ).toBe(
'%d bananes'
@@ -61,6 +68,8 @@ describe( 'i18n', () => {
} );
describe( '_nx', () => {
+ beforeEach( setDefaultLocalData );
+
it( 'use the plural form', () => {
expect(
_nx( '%d apple', '%d apples', 3, 'fruit', 'test_domain' )
@@ -74,7 +83,31 @@ describe( 'i18n', () => {
} );
} );
- describe( 'sprintf()', () => {
+ describe( 'isRTL', () => {
+ const ARLocaleData = {
+ '': {
+ plural_forms:
+ 'nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;',
+ language: 'ar',
+ localeSlug: 'ar',
+ },
+ 'text direction\u0004ltr': [ 'rtl' ],
+ Back: [ 'رجوع' ],
+ };
+
+ it( 'is false for non-rtl', () => {
+ expect( isRTL() ).toBe( false );
+ } );
+
+ it( 'is true for rtl', () => {
+ setLocaleData( ARLocaleData );
+ expect( isRTL() ).toBe( true );
+ } );
+ } );
+
+ describe( 'sprintf', () => {
+ beforeEach( setDefaultLocalData );
+
it( 'absorbs errors', () => {
// Disable reason: Failing case is the purpose of the test.
// eslint-disable-next-line @wordpress/valid-sprintf
@@ -93,6 +126,7 @@ describe( 'i18n', () => {
describe( 'setLocaleData', () => {
beforeAll( () => {
+ setDefaultLocalData();
setLocaleData( additionalLocaleData, 'test_domain' );
} );
@@ -147,3 +181,7 @@ describe( 'i18n', () => {
} );
} );
} );
+
+function setDefaultLocalData() {
+ setLocaleData( localeData, 'test_domain' );
+}