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

Multilingual #270

Draft
wants to merge 2 commits into
base: default
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 12 additions & 12 deletions src/MatchMaker.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const RecentGames = require('./RecentGames')

module.exports = class MatchMaker {
constructor (opts) {
this.waitingPair = null
this.waitingPair = {}
this.games = {}
this.wikiPages = opts.pages
this.recentGames = new RecentGames()
Expand All @@ -20,9 +20,9 @@ module.exports = class MatchMaker {
* Create a new game hosted by the given player.
*/

createGame (player) {
const [origin, goal] = this.wikiPages.randomPair()
const game = new WikiBattle(origin, goal)
async createGame (player, language) {
const [origin, goal] = await this.wikiPages.randomPair(language)
const game = new WikiBattle(origin, goal, language)
game.connect(player)
return game
}
Expand All @@ -32,11 +32,11 @@ module.exports = class MatchMaker {
* either the previous, or the next player that is passed to this method.
*/

pair (player) {
if (this.waitingPair) {
async pair (player, language) {
if (this.waitingPair[language]) {
debug('pairing with existing')
const game = this.waitingPair
this.waitingPair = null
const game = this.waitingPair[language]
this.waitingPair[language] = null

game.connect(player)

Expand All @@ -49,8 +49,8 @@ module.exports = class MatchMaker {
}

debug('waiting for pairing')
const game = this.createGame(player)
this.waitingPair = game
const game = await this.createGame(player, language)
this.waitingPair[language] = game

player.notifyJoinedGame(game)

Expand All @@ -63,10 +63,10 @@ module.exports = class MatchMaker {
* shareable URL.
*/

new (player) {
async new (player, language) {
debug('forcing new game')

const game = this.createGame(player)
const game = await this.createGame(player, language)
this.games[game.id] = game

player.notifyJoinedGame(game)
Expand Down
10 changes: 5 additions & 5 deletions src/SocketHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ module.exports = class SocketHandler {
const sock = new SocketEvents(raw)
const player = new Player(sock)

sock.on('gameType', (type, id) => {
sock.on('gameType', async (type, id, language) => {
switch (type) {
case 'pair':
game = this.matchMaker.pair(player)
game = await this.matchMaker.pair(player, language)
break
case 'new':
game = this.matchMaker.new(player)
game = await this.matchMaker.new(player, language)
break
case 'join':
try {
Expand All @@ -47,8 +47,8 @@ module.exports = class SocketHandler {
}
})

raw.on('close', () => {
if (game) {
raw.on('close', async () => {
if (await game) {
game.disconnect(player)

this.matchMaker.disconnected(game)
Expand Down
11 changes: 6 additions & 5 deletions src/WikiBattle.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ const BACKLINKS_TIMEOUT = ms('90 seconds')
*/

module.exports = class WikiBattle extends EventEmitter {
constructor (origin, goal) {
constructor (origin, goal, language) {
super()
this.id = generateId({ length: 7 })
this.players = []
this.origin = origin
this.goal = goal
this.language = language || 'en'
}

/**
Expand Down Expand Up @@ -87,7 +88,7 @@ module.exports = class WikiBattle extends EventEmitter {
*/

navigateInner (player, to) {
player.navigateTo(to)
player.navigateTo(to, null, this.language)
this.emitSocket('navigated', player.id, to)
this.checkWin()
}
Expand All @@ -102,7 +103,7 @@ module.exports = class WikiBattle extends EventEmitter {
return this.navigateInner(player, to)
}
// Check that the current article links to the next.
const page = await wiki.get(player.current())
const page = await wiki.get(player.current(), null, this.language)
if (page.linksTo(to)) {
this.navigateInner(player, to)
}
Expand All @@ -114,7 +115,7 @@ module.exports = class WikiBattle extends EventEmitter {

async sendHint () {
debug('sending hint for', this.goal)
const page = await wiki.get(this.goal)
const page = await wiki.get(this.goal, null, this.language)
this.emitSocket('hint', page.getHint())
}

Expand All @@ -125,7 +126,7 @@ module.exports = class WikiBattle extends EventEmitter {
async sendBacklinks () {
debug('sending backlinks for', this.goal)
try {
const page = await wiki.get(this.goal)
const page = await wiki.get(this.goal, null, this.language)
const back = await page.getBacklinks()
this.emitSocket('backlinks', null, back)
} catch (err) {
Expand Down
33 changes: 29 additions & 4 deletions src/WikiPages.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const event = require('p-event')
const ms = require('ms')
const getRandom = require('random-item')
const debug = require('debug')('WikiBattle:pages')
const qs = require('querystring')
const fetch = require('make-fetch-happen')

/**
* Possible starting and goal wikipedia articles manager.
Expand Down Expand Up @@ -55,16 +57,39 @@ module.exports = class WikiPages extends EventEmitter {
return getRandom(this.pages)
}

async translate (article, language) {
if (language === 'en') return article

const query = qs.stringify({
action: 'query',
format: 'json',
prop: 'langlinks',
titles: this.title,
lllang: language
})

const response = await fetch(`https://en.wikipedia.org/w/api.php?${query}`)
const body = await response.json()
const langlink = Object.values(body.query.pages)[0].langlinks

return langlink ? langlink[0]['*'] : null
}

/**
* Get a pair of random article names, guaranteed to be two different pages.
*/

randomPair () {
const one = this.random()
async randomPair (language) {
let one = null
let two = null

while (!(one && two)) {
one = one || await this.translate(this.random(), language)
two = two || await this.translate(this.random(), language)
}

let two = this.random()
while (one === two) {
two = this.random()
two = await this.translate(this.random(), language)
}

return [one, two]
Expand Down
15 changes: 12 additions & 3 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ app.use(t(async (req, res, next) => {
* Serve the application.
*/

function gameToJson ({ origin, goal, startedAt }) {
return { origin, goal, startedAt }
function gameToJson ({ origin, goal, startedAt, language }) {
return { origin, goal, startedAt, language }
}

app.get('/current', (req, res) => {
Expand All @@ -87,7 +87,16 @@ app.use(serveStatic(path.join(__dirname, '../public')))
*/

app.get('/wiki/:page', t(async (req, res) => {
const body = await wiki.get(req.params.page)
const body = await wiki.get(req.params.page, null, 'en')
res.end(body.content)
}))

/**
* Serve proxied Wikipedia articles in other languages than English.
*/

app.get('/wiki/:lang(\\w+)/:page', t(async (req, res) => {
const body = await wiki.get(req.params.page, null, req.params.lang)
res.end(body.content)
}))

Expand Down
6 changes: 6 additions & 0 deletions src/client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ <h3>Want to battle a friend?</h3>
<p> This will give you a game link you can share with your friend. </p>
<p id="go-priv">[Loading]</p>
</div>
<label for="language">Choose your language:</label> <!-- ToDo -->
<select name="language" id="language">
<option value="en">English</option>
<option value="de">Deutsch</option>
<option value="nl">Nederlands</option>
</select>
</div>

<h3>Like WikiBattle?</h3>
Expand Down
18 changes: 10 additions & 8 deletions src/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ const Player = newless(class Player {
this.path = []
}

navigateTo (page, cb) {
navigateTo (page, cb, language) {
this.path.push(page)
bus.emit('article-loading', { player: this, title: page })
loadPage(page, (e, body) => {
bus.emit('article-loaded', { player: this, title: page, body: body })
if (cb) cb(e)
})
}, language)
}
})

Expand All @@ -58,12 +58,14 @@ function init () {
const startGameWrapper = document.querySelector('#go')
const startGamePrivateWrapper = document.querySelector('#go-priv')

render(empty(startGameWrapper), startGameButton(false))
render(empty(startGamePrivateWrapper), startGameButton(true))
const language = document.querySelector('#language').value

render(empty(startGameWrapper), startGameButton(false, language))
render(empty(startGamePrivateWrapper), startGameButton(true, language))
bus.on('connect', go)
}

function go (isPrivate) {
function go (isPrivate, language) {
_private = isPrivate

bus.on('navigate', onNavigate)
Expand Down Expand Up @@ -124,7 +126,7 @@ function go (isPrivate) {
waiting()
})

sock.emit('gameType', connectType, connectId)
sock.emit('gameType', connectType, connectId, language)
}

function onNavigate (next) {
Expand Down Expand Up @@ -158,9 +160,9 @@ function onBacklinks (e, backlinks) {
bus.emit('backlinks', backlinks)
}

function onNavigated (playerId, page, cb) {
function onNavigated (playerId, page, cb, language) {
if (_players[playerId] && page !== null) {
_players[playerId].navigateTo(page, cb)
_players[playerId].navigateTo(page, cb, language)
}
}
function onOpponentScrolled (id, top, width) {
Expand Down
5 changes: 2 additions & 3 deletions src/client/load-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ const xhr = require('xhr')

const callbacks = {}

module.exports = function load (page, cb) {
module.exports = function load (page, cb, language) {
if (callbacks[page]) {
callbacks[page].push(cb)
return
}

callbacks[page] = [cb]

xhr(`./wiki/${page}`, (err, response) => {
xhr(`./wiki/${language}/${page}`, (err, response) => {
if (err) done(err)
else done(null, response.body)
})
Expand Down
9 changes: 5 additions & 4 deletions src/client/views/start-game-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ const render = require('crel')
const { on, off } = require('dom-event')
const bus = require('../bus')

module.exports = function startGameButton (isPrivate) {
return new StartGameButton(isPrivate).el
module.exports = function startGameButton (isPrivate, language) {
return new StartGameButton(isPrivate, language).el
}

class StartGameButton {
constructor (isPrivate) {
constructor (isPrivate, language) {
this.onClick = this.onClick.bind(this)

this.isPrivate = isPrivate
this.language = language

this.el = render('button', '» Go!')
on(this.el, 'click', this.onClick)
Expand All @@ -22,7 +23,7 @@ class StartGameButton {
}

onClick () {
bus.emit('connect', this.isPrivate)
bus.emit('connect', this.isPrivate, this.language)
this.disable()
}
}
Loading