Internationalizing the
(failing) New York
Times
WordCamp U.S.
(Donald J. Trump, President)
December 3, 2016
Scott Taylor
• Sr. Software Engineer, Web Frameworks

Formerly Interactive News

Formerly Blogs

The (failing) New York Times
• WordPress Core Developer
Why did we use WordPress?
• WordPress is bootstrapped with i18n
• Easy to support l10n by adding translation files
• Easy to separate languages using multisite
• For new products, helpful to be able to control the
front-end and the back-end
• Gulp plugins make it easy to generate PO/MO files
Gulp is a streaming
build system
• Tasks are written in code
instead of config (cough:
Grunt)
• gulp.pipe makes it easy to
chain tasks
const	po	=	new	PO();	
po.items	=	items;	
po.save(file);	
gulp.src(file)	
		.pipe(gettext())	
		.pipe(gulp.dest(dest))
Docker is the world’s leading software containerization
platform
Open-source system for automating deployment, scaling,
and management of containerized applications.
SNS
Amazon Simple Notification Service (Amazon SNS) is a
fast, flexible, fully managed push notification service
that lets you send individual messages or to fan-out
messages to large numbers of recipients
S3
Amazon Simple Storage Service (Amazon S3) is object
storage with a simple web service interface to store
and retrieve any amount of data from anywhere on the
web.
RDS
Amazon Relational Database Service (Amazon RDS)
makes it easy to set up, operate, and scale a relational
database in the cloud.
ElastiCache
Amazon ElastiCache is a web service that makes it easy
to deploy, operate, and scale an in-memory data store
or cache in the cloud.
What is a PHP
project?
gulp	
node_modules	
vendor	
wordpress/	
wp-content	
index.php	
wp-config.php	
.babelrc	
.eslintrc.json	
Dockerfile	
gulpfile.babel.js

composer.json	
composer.lock	
package.json	
yarn.lock
<?php	
require_once(	__DIR__	.	'/wp-config.php'	);	
wp();	
do_action(	'template_redirect'	);	
if	(	'HEAD'	===	$app['request']->getMethod()	&&	
		apply_filters(	'exit_on_http_head',	true	)	)	{	
		exit();	
}	
if	(	is_robots()	)	{	
		do_action(	'do_robots'	);	
}	elseif	(	is_feed()	)	{	
		do_feed();	
}	else	{	
		do_action(	'nyt_template_render',	$app	);	
}
Composer
Package
Management for
PHP
"prefer-dist":	true,	
				"sort-packages":	true	
		},	
		repositories":	[	
				{	
						"type":"composer",	
						"url":"https://wpackagist.org"	
				}	
		],	
		"require":	{	
				"aws/aws-sdk-php":	"^3.19",	
				"doctrine/orm":	"^2.5",	
				"guzzlehttp/guzzle":	"^6.2",	
				"monolog/monolog":	"^1.21",	
				"mustache/mustache":	"^2.11",	
				"pimple/pimple":	"^3.0",	
				"symfony/asset":	"^3.1",	
				"symfony/http-foundation":	"^3.1",	
				"symfony/validator":	"^3.1",	
				"wpackagist-plugin/akismet":	"^3.2",	
				"wpackagist-plugin/amp":	"^0.3.3",	
				"wpackagist-plugin/debug-bar":	"^0.8.4",	
				"wpackagist-plugin/debug-bar-console":	"^0.3.0",	
				"wpackagist-plugin/socialflow":	"^2.7"	
		},	
		"prefer-stable":	true,	
		"autoload":	{	
	 "psr-4":	{	
	 		"NYT"	:	"lib/php",	
	 		"NYTTheme":	"wp-content/themes/shell/php",	
	 		"NYTBylines"	:	"wp-content/plugins/nyt-wp-bylines/php",	
	 		"NYTMedia"	:	"wp-content/plugins/nyt-wp-media/php"	
				}
//	all	Composer	dependencies	are	available	
require(	__SRC__	.	'/vendor/autoload.php'	);	
//	Load	resource	in	the	DI	Container	
$app	=	new	NYTApp();	
$app->register(	new	NYTAppProvider()	);	
$app->register(	new	NYTCacheProvider()	);	
$app->register(	new	NYTDatabaseProvider()	);	
$app->register(	new	NYTSymfonyProvider()	);	
$app->register(	new	NYTAWSProvider()	);	
NYTgetApp(	$app	);
Mustache
}
Logic-less templates.
{{<	admin/layout	}}	
{{$	content	}}	
<div	class="wrap">	
	 <h1>	
	 	 {{	title	}}	
	 	 {{#	title_link_url	}}	
										<a	href="{{	.	}}"	class="page-title-action">{{	l10n.add_new	}}</a>	
									{{/	title_link_url	}}	
	 	 {{{	search	}}}	
	 </h1>	
	 {{#	message	}}	
	 <div	id="message"	class="updated	notice	is-dismissible">	
	 	 <p>{{{	.	}}}</p>	
	 </div>	
	 {{/	message	}}	
	 <form	id="posts-filter"	method="get">	
	 	 {{{	list_table_views	}}}	
	 	 {{{	list_table_display	}}}	
	 	 <div	id="ajax-response"></div>	
	 	 {{{	find_posts_div	}}}	
	 </form>	
</div>	
{{/	content	}}	
{{/	admin/layout	}}
Guzzle
Guzzle is a PHP HTTP client that makes it easy to send
HTTP requests and trivial to integrate with web services.
Symfony
Best-in-class PHP
Components
HttpFoundation
The component defines
an object-oriented layer
for the HTTP
specification.
Doctrine
• Around since 2006 with very stable, high-quality
codebase.
• Extremely flexible and powerful object-mapping and
query features.
• Support for both high-level and low-level database
programming for all use-cases.
• Large Community and integrations with many different
frameworks (Symfony, Zend Framework, CodeIgniter,
Flow, Lithium, etc)
Pimple
A Simple PHP Dependency Injection Container
$app['doctrine.connection']	=	function	(	$app	)	{	
		return	new	Connection(	
				[	
						'host'	=>	$app['db.host'],	
						'user'	=>	$app['db.user'],	
						'password'	=>	$app['db.password'],	
				],	
				$app['doctrine.nyt.driver'],	
				$app['doctrine.config']	
		);	
};	
$app['db']	=	function	(	$app	)	{	
		$conn	=	$app['doctrine.connection'];	
		return	EntityManager::create(		
				$conn,		
				$app['doctrine.config'],		
				$conn->getEventManager()		
		);	
};
<?php	
namespace	NYTCache;	
use	NYTApp;	
class	ObjectCache	implements	WPCacheInterface	{	
		public	function	__construct(	App	$app	)	{	
				$this->memcached	=	$app['memcached'];	
				$this->cache	=	$app['cache.chain'];	
				$this->arrayCache	=	$app['cache.array'];	
				$this->tablePrefix	=	$app['table_prefix'];	
				$this->globalPrefix	=	is_multisite()	?	''	:	$this->tablePrefix;	
				$this->sitePrefix	=	(	is_multisite()	?		
						$app['blog_id']	:		
						$this->tablePrefix	)	.	':';	
		}	
}
<?php	
namespace	NYTCache;	
interface	WPCacheInterface	{	
	 public	function	key(	$key,	string	$group	=	'default'	);	
	 public	function	get(	$id,	string	$group	=	'default'	);	
	 public	function	set(	$id,	$data,	string	$group	=	'default',	int	$expire	=	0	);	
	 public	function	add(	$id,	$data,	string	$group	=	'default',	int	$expire	=	0	);	
	 public	function	replace(	$id,	$data,	string	$group	=	'default',	int	$expire	=	0	);	
	 public	function	delete(	$id,	string	$group	=	'default'	);	
	 public	function	incr(	$id,	int	$n	=	1,	string	$group	=	'default'	);	
	 public	function	decr(	$id,	int	$n	=	1,	string	$group	=	'default'	);	
	 public	function	flush();	
	 public	function	close();	
	 public	function	switch_to_blog(	int	$blog_id	);	
	 public	function	add_global_groups(	$groups	);	
	 public	function	add_non_persistent_groups(	$groups	);	
}
Silex
A PHP microframework for
PHP. It is built on the
shoulders of Symfony and
Pimple and also inspired by
sinatra.
require_once('vendor/autoload.php');		
$app	=	new	SilexApplication();		
$app->get('/hello/{name}',	function($name)	use	($app)	{		
				return	'Hello	'	.	$app->escape($name);		
});		
$app->run();
Hack / HHVM
Hack is a programming language for HHVM, both from
Facebook.
Features of Hack
• Backwards compatibility with PHP
• Type annotations catch bugs before runtime.
• AsyncIO
• Collections
What are Collections?
$a	=	Vector	{'a',	'b',	'c'};
$b	=	Map	{	
		'a'	=>	888,		
		'b'	=>	23,		
		'f'	=>	0,	
};
$c	=	Set	{'A',	'B',	'C'};
Ordered sequence of values
Sequence of values keyed to string or int values:
Ordered collection of unique values (string or int)
What are Shapes?
type	Taco	=	shape(	
		'id'	=>	string,		
		'url'	=>	string,		
		'filling'	=>	string	
);	
$taco	=	shape(	
		'id'	=>	'573065673A34Y',		
		'url'	=>	'http://tacos.com',		
		'filling'	=>	'carnitas'	
);	
function	foo(Taco	$taco):	void	{	
		echo	$taco['filling'];	
		//	...	
}
The scope for errors is
significantly reduced.
Is WordPress a
PHP project?
JavaScript
A brave new world
Yarn
https://yarnpkg.com/
Improved package manager
for JavaScript, from Facebook
Install:
brew install yarn
Examples:
yarn add react
yarn install
yarn upgrade
https://code.facebook.com/posts/1840075619545360
Flow
A Static Type Checker for JavaScript
React
A JavaScript library for building user interfaces
Redux is a predictable state container for JavaScript apps.
Immutable collections for JavaScript
Relay
A JavaScript framework for building data-driven React
applications
GraphQL
A query language for your API
Atom is a text editor that's modern, approachable, yet
hackable to the core—a tool you can customize to do
anything but also use productively without ever
touching a config file.
Isomorphic Apps
http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/
http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/
A toolkit that
encapsulates and
manages the
configuration for
isomorphic web apps
//	@flow	
import	React	from	'react';	
import	styles	from	'./Loading.scss';	
const	Loading	=	()	=>	(	
		<p	className={styles.loading}>	
				Loading…	
		</p>	
);	
export	default	Loading;

Internationalizing The New York Times