Skip to content

Commit

Permalink
Framework: Add localization helpers to global wpcom instance
Browse files Browse the repository at this point in the history
  • Loading branch information
aduth committed Feb 18, 2016
1 parent 6176d54 commit aacb3b9
Show file tree
Hide file tree
Showing 7 changed files with 265 additions and 8 deletions.
3 changes: 3 additions & 0 deletions client/boot/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ var config = require( 'config' ),
accessibleFocus = require( 'lib/accessible-focus' ),
TitleStore = require( 'lib/screen-title/store' ),
renderWithReduxStore = require( 'lib/react-helpers' ).renderWithReduxStore,
bindWpLocaleState = require( 'lib/wp/localization' ).bindState,
// The following components require the i18n mixin, so must be required after i18n is initialized
Layout;

Expand Down Expand Up @@ -160,6 +161,8 @@ function boot() {
function reduxStoreReady( reduxStore ) {
let layoutSection, layout, layoutElement, validSections = [];

bindWpLocaleState( reduxStore );

if ( config.isEnabled( 'support-user' ) ) {
require( 'lib/user/support-user-interop' )( reduxStore );
}
Expand Down
14 changes: 9 additions & 5 deletions client/lib/wp/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const debug = debugFactory( 'calypso:wp' );
import wpcomUndocumented from 'lib/wpcom-undocumented';
import config from 'config';
import wpcomSupport from 'lib/wp/support';
import { injectLocalization } from './localization';

const addSyncHandlerWrapper = config.isEnabled( 'sync-handler' );
let wpcom;
Expand Down Expand Up @@ -40,11 +41,14 @@ if ( config.isEnabled( 'oauth' ) ) {
} );
}

if ( config.isEnabled( 'support-user' ) ) {
wpcom = wpcomSupport( wpcom );
}

// Inject localization helpers to `wpcom` instance
wpcom = injectLocalization( wpcom );

/**
* Expose `wpcom`
*/
if ( config.isEnabled( 'support-user' ) ) {
module.exports = wpcomSupport( wpcom );
} else {
module.exports = wpcom;
}
module.exports = wpcom;
10 changes: 10 additions & 0 deletions client/lib/wp/localization/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
REPORTER ?= spec
NODE_BIN := ../../../../node_modules/.bin
MOCHA ?= $(NODE_BIN)/mocha
BASE_DIR := $(NODE_BIN)/../..
NODE_PATH := $(BASE_DIR)/client

test:
@NODE_ENV=test NODE_PATH=$(NODE_PATH) $(MOCHA) --compilers jsx:babel/register,js:babel/register --reporter $(REPORTER)

.PHONY: test
16 changes: 16 additions & 0 deletions client/lib/wp/localization/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
wpcom.js Localization
=====================

This module enables the extension of a `wpcom.js` instance to include localization helper functions. Specifically, the modified instance will include a new `withLocale` function, which will result in the subsequent chained request being localized according to the current user's preferred locale.

## Usage

The helper is already bound for the global instance of `wpcom.js` used in Calypso. To take advantage of the localization helpers, call the `withLocale` function at the start of your request chain.

```js
import wpcom from 'lib/wp';

wpcom.withLocale().site( siteId ).postTypesList().then( ( data ) => {
// `data` is a localized response
} );
```
74 changes: 74 additions & 0 deletions client/lib/wp/localization/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* External dependencies
*/
import qs from 'querystring';

/**
* Internal dependencies
*/
import { getCurrentUserLocale } from 'state/current-user/selectors';

/**
* Module variables
*/
let locale;

/**
* Given a WPCOM parameter set, modifies the query such that a non-default
* locale is added to the query parameter.
*
* @param {Object} params Original parameters
* @return {Object} Revised parameters, if non-default locale
*/
export function addLocaleQueryParam( params ) {
if ( ! locale || 'en' === locale ) {
return params;
}

let query = qs.parse( params.query );
return Object.assign( params, {
query: qs.stringify( Object.assign( query, { locale } ) )
} );
};

/**
* Modifies a WPCOM instance, returning an updated instance with included
* localization helpers. Specifically, this adds a new `withLocale` method to
* the base instance for indicating the request should be localized.
*
* @param {Object} wpcom Original WPCOM instance
* @return {Object} Modified WPCOM instance with localization helpers
*/
export function injectLocalization( wpcom ) {
const request = wpcom.request.bind( wpcom );
return Object.assign( wpcom, {
withLocale: function() {
this.localize = true;
return this;
},

request: function( params, callback ) {
if ( this.localize ) {
this.localize = false;
return request( addLocaleQueryParam( params ), callback );
}

return request( params, callback );
}
} );
}

/**
* Subscribes to the provided Redux store instance, updating the known locale
* value to the latest value when state changes.
*
* @param {Object} store Redux store instance
*/
export function bindState( store ) {
function setLocale() {
locale = getCurrentUserLocale( store.getState() );
}

store.subscribe( setLocale );
setLocale();
}
146 changes: 146 additions & 0 deletions client/lib/wp/localization/test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/**
* External dependencies
*/
import { expect } from 'chai';
import rewire from 'rewire';
import mockery from 'mockery';
import sinon from 'sinon';

describe( 'localization', () => {
let localization, addLocaleQueryParam, injectLocalization, bindState;
let getCurrentUserLocaleMock = sinon.stub();

before( () => {
// Mock user locale state selector
mockery.enable( {
warnOnReplace: false,
warnOnUnregistered: false
} );
mockery.registerMock( 'state/current-user/selectors', {
getCurrentUserLocale: () => getCurrentUserLocaleMock()
} );

// Prepare module for rewiring
localization = rewire( '../' );
addLocaleQueryParam = localization.addLocaleQueryParam;
injectLocalization = localization.injectLocalization;
bindState = localization.bindState;
} );

beforeEach( () => {
localization.__set__( 'locale', undefined );
} );

after( function() {
mockery.disable();
} );

describe( '#addLocaleQueryParam()', () => {
it( 'should not modify params if locale unknown', () => {
const params = addLocaleQueryParam( { query: 'search=foo' } );

expect( params ).to.eql( { query: 'search=foo' } );
} );

it( 'should not modify params if locale is default', () => {
localization.__set__( 'locale', 'en' );
const params = addLocaleQueryParam( { query: 'search=foo' } );

expect( params ).to.eql( { query: 'search=foo' } );
} );

it( 'should include the locale query parameter for a non-default locale', () => {
localization.__set__( 'locale', 'fr' );
const params = addLocaleQueryParam( { query: 'search=foo' } );

expect( params ).to.eql( {
query: 'search=foo&locale=fr'
} );
} );
} );

describe( '#injectLocalization()', () => {
it( 'should return a modified object', () => {
let wpcom = { request() {} };
injectLocalization( wpcom );

expect( wpcom.withLocale ).to.be.a( 'function' );
} );

it( 'should override the default request method', () => {
const request = () => {};
let wpcom = { request };
injectLocalization( wpcom );

expect( wpcom.request ).to.not.equal( request );
} );

it( 'should not modify params if `withLocale` not used', ( done ) => {
localization.__set__( 'locale', 'fr' );
let wpcom = {
request( params ) {
expect( params.query ).to.equal( 'search=foo' );
done();
}
};

injectLocalization( wpcom );
wpcom.request( { query: 'search=foo' } );
} );

it( 'should modify params if `withLocale` is used', ( done ) => {
localization.__set__( 'locale', 'fr' );
let wpcom = {
request( params ) {
expect( params.query ).to.equal( 'search=foo&locale=fr' );
done();
}
};

injectLocalization( wpcom );
wpcom.withLocale().request( { query: 'search=foo' } );
} );

it( 'should not modify the request after `withLocale` is used', ( done ) => {
localization.__set__( 'locale', 'fr' );
let assert = false;
let wpcom = {
request( params ) {
if ( ! assert ) {
return;
}

expect( params.query ).to.equal( 'search=foo' );
done();
}
};

injectLocalization( wpcom );
wpcom.withLocale().request( { query: 'search=foo' } );
assert = true;
wpcom.request( { query: 'search=foo' } );
} );
} );

describe( '#bindState()', () => {
it( 'should set initial locale from state', () => {
getCurrentUserLocaleMock = sinon.stub().returns( 'fr' );
bindState( { subscribe() {}, getState() {} } );
expect( localization.__get__( 'locale' ) ).to.equal( 'fr' );
} );

it( 'should subscribe to the store, setting locale on change', () => {
let listener;
bindState( {
subscribe( _listener ) {
listener = _listener;
},
getState() {}
} );
getCurrentUserLocaleMock = sinon.stub().returns( 'de' );
listener();

expect( localization.__get__( 'locale' ) ).to.equal( 'de' );
} );
} );
} );
10 changes: 7 additions & 3 deletions client/lib/wp/node.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
/**
* Internal dependencies
*/
var wpcom = require( 'lib/wpcom-undocumented' );
var config = require( 'config' );
import wpcomUndocumented from 'lib/wpcom-undocumented';
import config from 'config';
import { injectLocalization } from './localization';

wpcom = wpcom( require( 'wpcom-xhr-request' ) );
let wpcom = wpcomUndocumented( require( 'wpcom-xhr-request' ) );

if ( config.isEnabled( 'support-user' ) ) {
wpcom = require( 'lib/wp/support' )( wpcom );
}

// Inject localization helpers to `wpcom` instance
wpcom = injectLocalization( wpcom );

module.exports = wpcom;

0 comments on commit aacb3b9

Please sign in to comment.