@hmcts/one-per-page
Advanced tools
Comparing version 3.0.0-2 to 3.0.0
@@ -1,10 +0,20 @@ | ||
<a name="3.0.0-2"></a> | ||
# 3.0.0-2 (2018-02-27) | ||
<a name="3.0.0"></a> | ||
# 3.0.0 (2018-03-06) | ||
* Add a function to list the available languages ([ff32db7](https://github.com/hmcts/one-per-page/commit/ff32db7)) | ||
* Add debugging of step instance creation ([0105488](https://github.com/hmcts/one-per-page/commit/0105488)) | ||
* Add documentation for the language switcher ([dd8b775](https://github.com/hmcts/one-per-page/commit/dd8b775)) | ||
* Add logging to BaseStep ([f506cc4](https://github.com/hmcts/one-per-page/commit/f506cc4)) | ||
* Add logging to error pages ([013eecd](https://github.com/hmcts/one-per-page/commit/013eecd)) | ||
* Ensure refs aren't included in checking if an answer has been given ([c4f307d](https://github.com/hmcts/one-per-page/commit/c4f307d)) | ||
* Fix heroku deployments ([94bf3d6](https://github.com/hmcts/one-per-page/commit/94bf3d6)) | ||
* Fix heroku deployments ([e434590](https://github.com/hmcts/one-per-page/commit/e434590)) | ||
* Fix heroku deployments ([520243c](https://github.com/hmcts/one-per-page/commit/520243c)) | ||
* Fix heroku deployments ([4a0808b](https://github.com/hmcts/one-per-page/commit/4a0808b)) | ||
* Fix heroku deployments ([e143c28](https://github.com/hmcts/one-per-page/commit/e143c28)) | ||
* Ignore webpack built assets in example app ([b68cf0f](https://github.com/hmcts/one-per-page/commit/b68cf0f)) | ||
* Include the language switcher styles in example app ([4f3dde7](https://github.com/hmcts/one-per-page/commit/4f3dde7)) | ||
* Increase coverage over i18Next.js ([cbbe369](https://github.com/hmcts/one-per-page/commit/cbbe369)) | ||
* Make form capable of retrieving values from a temp storage ([7cea8f2](https://github.com/hmcts/one-per-page/commit/7cea8f2)) | ||
* Move currentLang / availableLangs to req.i18n ([fb2c82a](https://github.com/hmcts/one-per-page/commit/fb2c82a)) | ||
* Omit dist folders from eslint ([f489757](https://github.com/hmcts/one-per-page/commit/f489757)) | ||
@@ -14,14 +24,32 @@ * Prevent caching of questions ([8f357a4](https://github.com/hmcts/one-per-page/commit/8f357a4)) | ||
* Redirect to GET on errors ([0fa6733](https://github.com/hmcts/one-per-page/commit/0fa6733)) | ||
* Release 3.0.0-1 ([b75bfce](https://github.com/hmcts/one-per-page/commit/b75bfce)) | ||
* Release 2.6.0 ([302e691](https://github.com/hmcts/one-per-page/commit/302e691)) | ||
* Remove old field types and underlying classes ([2f384e6](https://github.com/hmcts/one-per-page/commit/2f384e6)) | ||
* Shim over @hmcts/nodejs-logging for logging ([9b3a483](https://github.com/hmcts/one-per-page/commit/9b3a483)) | ||
* Switch action logging to new module ([28c00de](https://github.com/hmcts/one-per-page/commit/28c00de)) | ||
* Switch language based on url params ([8e19bae](https://github.com/hmcts/one-per-page/commit/8e19bae)) | ||
* Switch logging in journey to use new logging module ([e6016b0](https://github.com/hmcts/one-per-page/commit/e6016b0)) | ||
* Update tech-docs and fix issue where it couldn't see css-loader in heroku ([b01e78c](https://github.com/hmcts/one-per-page/commit/b01e78c)) | ||
<a name="3.0.0-1"></a> | ||
# 3.0.0-1 (2018-02-23) | ||
<a name="2.6.0"></a> | ||
# 2.6.0 (2018-03-06) | ||
* Add a function to list the available languages ([ff32db7](https://github.com/hmcts/one-per-page/commit/ff32db7)) | ||
* Add debugging of step instance creation ([0105488](https://github.com/hmcts/one-per-page/commit/0105488)) | ||
* Add documentation for the language switcher ([dd8b775](https://github.com/hmcts/one-per-page/commit/dd8b775)) | ||
* Add logging to BaseStep ([f506cc4](https://github.com/hmcts/one-per-page/commit/f506cc4)) | ||
* Add logging to error pages ([013eecd](https://github.com/hmcts/one-per-page/commit/013eecd)) | ||
* Ensure refs aren't included in checking if an answer has been given ([c4f307d](https://github.com/hmcts/one-per-page/commit/c4f307d)) | ||
* Fix heroku deployments ([520243c](https://github.com/hmcts/one-per-page/commit/520243c)) | ||
* Fix heroku deployments ([94bf3d6](https://github.com/hmcts/one-per-page/commit/94bf3d6)) | ||
* Fix heroku deployments ([e434590](https://github.com/hmcts/one-per-page/commit/e434590)) | ||
* Fix heroku deployments ([4a0808b](https://github.com/hmcts/one-per-page/commit/4a0808b)) | ||
* Fix heroku deployments ([e143c28](https://github.com/hmcts/one-per-page/commit/e143c28)) | ||
* Ignore webpack built assets in example app ([b68cf0f](https://github.com/hmcts/one-per-page/commit/b68cf0f)) | ||
* Include the language switcher styles in example app ([4f3dde7](https://github.com/hmcts/one-per-page/commit/4f3dde7)) | ||
* Increase coverage over i18Next.js ([cbbe369](https://github.com/hmcts/one-per-page/commit/cbbe369)) | ||
* Make form capable of retrieving values from a temp storage ([7cea8f2](https://github.com/hmcts/one-per-page/commit/7cea8f2)) | ||
* Move currentLang / availableLangs to req.i18n ([fb2c82a](https://github.com/hmcts/one-per-page/commit/fb2c82a)) | ||
* Omit dist folders from eslint ([f489757](https://github.com/hmcts/one-per-page/commit/f489757)) | ||
* Prevent caching of questions ([8f357a4](https://github.com/hmcts/one-per-page/commit/8f357a4)) | ||
@@ -31,2 +59,7 @@ * Provide a way to temporarily store values ([b558a2f](https://github.com/hmcts/one-per-page/commit/b558a2f)) | ||
* Remove old field types and underlying classes ([2f384e6](https://github.com/hmcts/one-per-page/commit/2f384e6)) | ||
* Shim over @hmcts/nodejs-logging for logging ([9b3a483](https://github.com/hmcts/one-per-page/commit/9b3a483)) | ||
* Switch action logging to new module ([28c00de](https://github.com/hmcts/one-per-page/commit/28c00de)) | ||
* Switch language based on url params ([8e19bae](https://github.com/hmcts/one-per-page/commit/8e19bae)) | ||
* Switch logging in journey to use new logging module ([e6016b0](https://github.com/hmcts/one-per-page/commit/e6016b0)) | ||
* Update tech-docs and fix issue where it couldn't see css-loader in heroku ([b01e78c](https://github.com/hmcts/one-per-page/commit/b01e78c)) | ||
@@ -33,0 +66,0 @@ |
@@ -110,2 +110,37 @@ # Page | ||
#### Switching languages in your pages | ||
You can add a language switcher to your pages to allow the user to choose which | ||
language to view the page in. | ||
The [look-and-feel] package provides a handy macro for switching languages: | ||
![Example of the language switcher](/docs/images/lang-switch.png) | ||
To use this switcher you can import `languageSwitch` from [look-and-feel]: | ||
_MyPage.template.html_ | ||
```djangohtml | ||
{% extends "look-and-feel/layouts/two_thirds.html" %} | ||
{% from "look-and-feel/components/i18n.njk" import languageSwitch %} | ||
{% block breadcrumbs %} | ||
{{ languageSwitch(i18n.availableLanguages, i18n.currentLanguage) }} | ||
{% endblock %} | ||
``` | ||
And add the following import to your sass file to ensure you get the correct | ||
styling: | ||
_main.scss_ | ||
```sass | ||
@import 'look-and-feel/language-switch'; | ||
``` | ||
This switcher presents a link for each language that you have made available for | ||
that particular page. | ||
> The `question.html`, `check_your_answers.html` and `add_another.html` templates | ||
> provide this language switcher by default | ||
### Template locals | ||
@@ -192,3 +227,4 @@ | ||
[i18Next]: https://www.i18next.com/ | ||
[look-and-feel]: https://github.com/hmcts/look-and-feel | ||
[IETF language tag]: https://en.wikipedia.org/wiki/IETF_language_tag | ||
[resolveTemplate]: /docs/middleware/resolveTemplate |
@@ -5,3 +5,3 @@ { | ||
"homepage": "https://github.com/hmcts/one-per-page#readme", | ||
"version": "3.0.0-2", | ||
"version": "3.0.0", | ||
"main": "./src/main.js", | ||
@@ -22,2 +22,3 @@ "repository": { | ||
"connect-redis": "^3.3.2", | ||
"cookie-parser": "^1.4.3", | ||
"debug": "^3.1.0", | ||
@@ -41,3 +42,3 @@ "deepmerge": "^2.0.1", | ||
"@hmcts/eslint-config": "^1.3.0", | ||
"@hmcts/tech-docs": "^0.3.0", | ||
"@hmcts/tech-docs": "^0.4.0", | ||
"chai": "^4.1.0", | ||
@@ -64,4 +65,5 @@ "chai-as-promised": "^7.1.1", | ||
"docs": "tech-docs --use-http --watch", | ||
"heroku-postbuild": "yarn add @hmcts/tech-docs", | ||
"heroku-postbuild": "yarn remove @hmcts/tech-docs; yarn add @hmcts/tech-docs", | ||
"lint": "eslint .", | ||
"serve-docs": "tech-docs -p $PORT -d $URL", | ||
"test": "NODE_PATH=. NODE_ENV=testing nyc --reporter=text-summary mocha --exit 'test/**/*.test.js'" | ||
@@ -68,0 +70,0 @@ }, |
@@ -9,2 +9,3 @@ const session = require('../session'); | ||
const log = require('../util/logging')('journey'); | ||
const cookieParser = require('cookie-parser'); | ||
@@ -69,2 +70,3 @@ const parseUrl = baseUrl => { | ||
app.use(cookieParser()); | ||
app.use(setupMiddleware); | ||
@@ -71,0 +73,0 @@ app.use(opts.session); |
const i18Next = require('i18next'); | ||
const { defined } = require('../util/checks'); | ||
const defaultIfUndefined = require('../util/defaultIfUndefined'); | ||
@@ -7,9 +8,35 @@ const i18NextInstance = i18Next.init({ fallbackLng: 'en' }); | ||
const i18nMiddleware = (req, res, next) => { | ||
if (defined(req.i18Next)) { | ||
next(); | ||
return; | ||
if (!defined(req.i18Next)) { | ||
req.i18Next = i18NextInstance; | ||
} | ||
req.i18Next = i18NextInstance; | ||
if (!defined(req.i18n)) { | ||
req.i18n = { | ||
t: i18NextInstance.t.bind(i18NextInstance), | ||
get availableLanguages() { | ||
const ns = req.currentStep.name; | ||
const allLangs = Object.keys(req.i18Next.services.resourceStore.data); | ||
return allLangs | ||
.filter(lang => ns in req.i18Next.services.resourceStore.data[lang]) | ||
.map(lang => { | ||
return { code: lang, name: req.i18Next.t(lang) }; | ||
}); | ||
}, | ||
get currentLanguage() { | ||
return defaultIfUndefined(req.i18Next.language, 'en'); | ||
} | ||
}; | ||
} | ||
if (defined(req.query) && defined(req.query.lng)) { | ||
req.i18Next.changeLanguage(req.query.lng); | ||
} else if (defined(req.cookies) && defined(req.cookies.i18n)) { | ||
req.i18Next.changeLanguage(req.cookies.i18n); | ||
} else { | ||
req.i18Next.changeLanguage('en'); | ||
} | ||
res.cookie('i18n', defaultIfUndefined(req.i18Next.language, 'en')); | ||
next(); | ||
@@ -16,0 +43,0 @@ }; |
@@ -69,2 +69,6 @@ const BaseStep = require('./BaseStep'); | ||
get i18n() { | ||
return this.req.i18n; | ||
} | ||
handler(req, res) { | ||
@@ -71,0 +75,0 @@ if (req.method === 'GET') { |
@@ -1,2 +0,2 @@ | ||
const { expect } = require('../util/chai'); | ||
const { expect, sinon } = require('../util/chai'); | ||
const { i18NextInstance, i18nMiddleware } = require('../../src/i18n/i18Next'); | ||
@@ -12,4 +12,4 @@ | ||
const executeMiddleware = ({ | ||
req = {}, | ||
res = {} | ||
req = { cookies: {} }, | ||
res = { cookie: sinon.stub() } | ||
} = {}) => new Promise((resolve, reject) => { | ||
@@ -27,3 +27,4 @@ const next = error => { | ||
it('does nothing if req.i18Next exists', () => { | ||
return executeMiddleware({ req: { i18Next: {} } }) | ||
const fakeI18Next = { changeLanguage: sinon.stub(), language: 'en' }; | ||
return executeMiddleware({ req: { i18Next: fakeI18Next } }) | ||
.then(({ req }) => expect(req.i18Next).to.not.eql(i18NextInstance)); | ||
@@ -36,2 +37,115 @@ }); | ||
}); | ||
it('attaches i18n to req', () => { | ||
return executeMiddleware().then(({ req }) => { | ||
expect(req.i18n).to.be.an('object'); | ||
expect(req.i18n.t).to.be.a('function'); | ||
}); | ||
}); | ||
it('defaults the current language to english', () => { | ||
const req = { | ||
i18Next: { changeLanguage: sinon.stub(), language: 'en' }, | ||
cookies: {} | ||
}; | ||
const res = { cookie: sinon.stub() }; | ||
return executeMiddleware({ req, res }).then(() => { | ||
expect(req.i18Next.changeLanguage).calledWith('en'); | ||
}); | ||
}); | ||
it('defaults the current language to english if i18n has no lang', () => { | ||
const req = { | ||
i18Next: { changeLanguage: sinon.stub() }, | ||
cookies: {} | ||
}; | ||
const res = { cookie: sinon.stub() }; | ||
return executeMiddleware({ req, res }).then(() => { | ||
expect(req.i18Next.changeLanguage).calledWith('en'); | ||
expect(res.cookie).calledWith('i18n', 'en'); | ||
}); | ||
}); | ||
it('sets the current language if req.param.lng is present', () => { | ||
const req = { | ||
i18Next: { changeLanguage: sinon.stub(), language: 'en' }, | ||
cookies: {}, | ||
query: { lng: 'cy' } | ||
}; | ||
const res = { cookie: sinon.stub() }; | ||
return executeMiddleware({ req, res }).then(() => { | ||
expect(req.i18Next.changeLanguage).calledWith('cy'); | ||
}); | ||
}); | ||
it('sets the current language i18n cookie is present', () => { | ||
const req = { | ||
i18Next: { changeLanguage: sinon.stub(), language: 'en' }, | ||
cookies: { i18n: 'cy' } | ||
}; | ||
const res = { cookie: sinon.stub() }; | ||
return executeMiddleware({ req, res }).then(() => { | ||
expect(req.i18Next.changeLanguage).calledWith('cy'); | ||
}); | ||
}); | ||
describe('req.i18n.availableLanguages', () => { | ||
it('returns all langs that have content for the current step', () => { | ||
const i18Next = { | ||
t: sinon.stub(), | ||
changeLanguage: sinon.stub(), | ||
language: 'en', | ||
services: { | ||
resourceStore: { | ||
// eslint-disable-next-line id-blacklist | ||
data: { | ||
en: { FooStep: {} }, | ||
cy: { FooStep: {} } | ||
} | ||
} | ||
} | ||
}; | ||
const currentStep = { name: 'FooStep' }; | ||
const expected = [ | ||
{ code: 'en', name: 'English' }, | ||
{ code: 'cy', name: 'Welsh' } | ||
]; | ||
i18Next.t.withArgs('en').returns('English'); | ||
i18Next.t.withArgs('cy').returns('Welsh'); | ||
return executeMiddleware({ req: { i18Next, currentStep } }) | ||
.then(({ req }) => | ||
expect(req.i18n.availableLanguages).to.eql(expected) | ||
); | ||
}); | ||
}); | ||
describe('req.i18n.currentLanguage', () => { | ||
it('returns the language currently used by i18Next', () => { | ||
const i18Next = { | ||
t: sinon.stub(), | ||
changeLanguage: sinon.stub(), | ||
language: 'cy' | ||
}; | ||
const currentStep = { name: 'FooStep' }; | ||
return executeMiddleware({ req: { i18Next, currentStep } }) | ||
.then(({ req }) => { | ||
expect(req.i18n.currentLanguage).to.eql('cy'); | ||
}); | ||
}); | ||
it('defaults to english if no i18Next has no chosen language', () => { | ||
const i18Next = { | ||
t: sinon.stub(), | ||
changeLanguage: sinon.stub() | ||
}; | ||
const currentStep = { name: 'FooStep' }; | ||
return executeMiddleware({ req: { i18Next, currentStep } }) | ||
.then(({ req }) => { | ||
expect(req.i18n.currentLanguage).to.eql('en'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -38,0 +152,0 @@ |
@@ -11,2 +11,3 @@ const express = require('express'); | ||
const { RequestBoundJourney } = require('../../src/flow'); | ||
const cookieParser = require('cookie-parser'); | ||
@@ -26,6 +27,3 @@ function testApp(views = []) { | ||
const cookie = res => { | ||
const setCookie = res.headers['set-cookie']; | ||
return (setCookie && setCookie[0]) || undefined; | ||
}; | ||
const cookies = res => res.headers['set-cookie'] || []; | ||
@@ -50,2 +48,3 @@ const _supertest = Symbol('supertest'); | ||
app.use(session({ baseUrl: '127.0.0.1', secret: 'keyboard cat' })); | ||
app.use(cookieParser()); | ||
app.use(i18nMiddleware); | ||
@@ -79,6 +78,6 @@ | ||
return supertestObj.then(res => { | ||
const sid = cookie(res); | ||
// const sid = cookies(res); | ||
return supertest(supertestObj.app) | ||
.get('/supertest-check-session') | ||
.set('Cookie', sid) | ||
.set('Cookie', cookies(res)) | ||
.expect(200); | ||
@@ -93,7 +92,7 @@ }).then(res => { | ||
const shouldNotSetCookie = name => { | ||
return res => Promise.all([ | ||
expect(Object.keys(res.headers)).to.not.include('set-cookie'), | ||
expect(res.headers['set-cookie']).to.not.include.match(name) | ||
]); | ||
const shouldNotSetCookie = name => res => { | ||
if (typeof res.headers['set-cookie'] !== 'undefined') { | ||
return expect(res.headers['set-cookie']).to.not.include.match(name); | ||
} | ||
return expect(Object.keys(res.headers)).to.not.include('set-cookie'); | ||
}; | ||
@@ -100,0 +99,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
1313272
244
8208
0
22
+ Addedcookie-parser@^1.4.3
+ Addedcookie-parser@1.4.7(transitive)