diff --git a/i18n.js b/i18n.js new file mode 100644 index 0000000..018788e --- /dev/null +++ b/i18n.js @@ -0,0 +1,6 @@ +const NextI18Next = require('next-i18next').default + +module.exports = new NextI18Next({ + defaultLanguage: 'nl', + otherLanguages: ['en'], +}) diff --git a/package-lock.json b/package-lock.json index 83beb8d..9f5fdb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2295,6 +2295,11 @@ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" + }, "core-js-compat": { "version": "3.6.5", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", @@ -2763,6 +2768,11 @@ "minimalistic-assert": "^1.0.0" } }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==" + }, "detective": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", @@ -3485,6 +3495,14 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, "hsl-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", @@ -3500,6 +3518,14 @@ "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==" }, + "html-parse-stringify2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz", + "integrity": "sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=", + "requires": { + "void-elements": "^2.0.1" + } + }, "htmlparser2": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", @@ -3518,11 +3544,54 @@ } } }, + "http-errors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.4.0.tgz", + "integrity": "sha1-bAJC3qaz33r9oVPHEImzHG6Cqr8=", + "requires": { + "inherits": "2.0.1", + "statuses": ">= 1.2.1 < 2" + } + }, "https-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, + "i18next": { + "version": "19.4.4", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-19.4.4.tgz", + "integrity": "sha512-ofaHtdsDdX3A5nYur1HWblB7J4hIcjr2ACdnwTAJgc8hTfPbyzZfGX0hVkKpI3vzDIgO6Uzc4v1ffW2W6gG6zw==", + "requires": { + "@babel/runtime": "^7.3.1" + } + }, + "i18next-browser-languagedetector": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-4.1.1.tgz", + "integrity": "sha512-akv0zurR/2KU7s1qaWkirY9FEEOT1TNsQaezEg8+1BLLQre7vylqb7tYoUgYqP/0/BEzXJgnoQnj+sh5xYFMhg==", + "requires": { + "@babel/runtime": "^7.5.5" + } + }, + "i18next-fs-backend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-1.0.3.tgz", + "integrity": "sha512-ppSvicYolLrWEVQ7Eb27708GFYikq1bXGM9Wmz/5faM6V2nvhnHPP3fDLQ26E2cNZAKGeT/9znK08jSgei4leA==" + }, + "i18next-http-backend": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-1.0.10.tgz", + "integrity": "sha512-HQl3N2plhU7WQd2Bcq3UWrpgM01w/Lkee76airTsKsLG4jnWKy6mYH3O7xz1da2ga9R6AN1MTSVVzJTp0uDl7A==", + "requires": { + "node-fetch": "2.6.0" + } + }, + "i18next-http-middleware": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/i18next-http-middleware/-/i18next-http-middleware-1.0.6.tgz", + "integrity": "sha512-SMMe3Lnn2lPk/qlZ02qO2fm50Rx3f4c9puLxa3L5nxLthZrIKCI3HHmrJddJZIKI2RW2Im+Vr8597g7A9W+mFQ==" + }, "icss-utils": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", @@ -4332,6 +4401,25 @@ "webpack-sources": "1.4.3" } }, + "next-i18next": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-4.4.2.tgz", + "integrity": "sha512-J7A0x4MFqDw2O2nJGId98pmeSTNwRpMHTSNboi4xeQsvl4PN5T3MrA/LZN0GJCa8rsRWR63dkNVYN8fx5OOg1A==", + "requires": { + "core-js": "^2", + "detect-node": "^2.0.4", + "hoist-non-react-statics": "^3.2.0", + "i18next": "^19.0.3", + "i18next-browser-languagedetector": "^4.0.0", + "i18next-fs-backend": "^1.0.2", + "i18next-http-backend": "^1.0.8", + "i18next-http-middleware": ">=1.0.2", + "path-match": "^1.2.4", + "prop-types": "^15.6.2", + "react-i18next": "^11.0.0", + "url": "^0.11.0" + } + }, "next-tick": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", @@ -4645,11 +4733,35 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, + "path-match": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/path-match/-/path-match-1.2.4.tgz", + "integrity": "sha1-pidH88fgwlFHYml/JEQ1hbCRAOo=", + "requires": { + "http-errors": "~1.4.0", + "path-to-regexp": "^1.0.0" + } + }, "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + } + } + }, "pbkdf2": { "version": "3.0.17", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", @@ -5871,6 +5983,15 @@ "scheduler": "^0.19.1" } }, + "react-i18next": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.4.0.tgz", + "integrity": "sha512-lyOZSSQkif4H9HnHN3iEKVkryLI+WkdZSEw3VAZzinZLopfYRMHVY5YxCopdkXPLEHs6S5GjKYPh3+j0j336Fg==", + "requires": { + "@babel/runtime": "^7.3.1", + "html-parse-stringify2": "2.0.1" + } + }, "react-is": { "version": "16.8.6", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", @@ -6521,6 +6642,11 @@ } } }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, "stream-browserify": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", @@ -7266,6 +7392,11 @@ "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" + }, "watchpack": { "version": "2.0.0-beta.13", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.0.0-beta.13.tgz", diff --git a/package.json b/package.json index 98527ec..7c2e8a4 100644 --- a/package.json +++ b/package.json @@ -5,12 +5,13 @@ "scripts": { "dev": "next dev -p 4080", "build": "next build", - "start": "next start" + "start": "NODE_ENV=production node server.js" }, "dependencies": { "isomorphic-unfetch": "^3.0.0", "lodash": "^4.17.15", "next": "9.3.5", + "next-i18next": "^4.4.2", "react": "16.13.1", "react-dom": "16.13.1" }, diff --git a/pages/_app.js b/pages/_app.js index 193f85e..170c386 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -1,7 +1,14 @@ import '../styles/index.css' +import App from 'next/app' +import { appWithTranslation } from '../i18n' function MyApp({ Component, pageProps }) { return } -export default MyApp +MyApp.getInitialProps = async (appContext) => { + const appProps = await App.getInitialProps(appContext) + return { ...appProps } +} + +export default appWithTranslation(MyApp) diff --git a/pages/_error.js b/pages/_error.js new file mode 100644 index 0000000..b13ed10 --- /dev/null +++ b/pages/_error.js @@ -0,0 +1,36 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import { withTranslation } from '../i18n' + +const Error = ({ statusCode, t }) => ( +

+ {statusCode + ? t('error-with-status', { statusCode }) + : t('error-without-status')} +

+) + +Error.getInitialProps = async ({ res, err }) => { + let statusCode = null + if (res) { + ({ statusCode } = res) + } else if (err) { + ({ statusCode } = err) + } + return { + namespacesRequired: ['common'], + statusCode, + } +} + +Error.defaultProps = { + statusCode: null, +} + +Error.propTypes = { + statusCode: PropTypes.number, + t: PropTypes.func.isRequired, +} + +export default withTranslation('common')(Error) diff --git a/pages/courses/[course]/index.js b/pages/courses/[course]/index.js index f68c324..cd6c685 100644 --- a/pages/courses/[course]/index.js +++ b/pages/courses/[course]/index.js @@ -14,4 +14,12 @@ function CourseDetails() { ) } +export async function getStaticProps(context) { + return { + props: { + namespacesRequired: ['common'], + }, + } +} + export default CourseDetails diff --git a/pages/courses/[course]/learn/index.js b/pages/courses/[course]/learn/index.js index bafb29f..d549ce4 100644 --- a/pages/courses/[course]/learn/index.js +++ b/pages/courses/[course]/learn/index.js @@ -14,4 +14,12 @@ function CourseDetails() { ) } +export async function getStaticProps(context) { + return { + props: { + namespacesRequired: ['common'], + }, + } +} + export default CourseDetails diff --git a/pages/courses/[course]/learn/units/[unit]/index.js b/pages/courses/[course]/learn/units/[unit]/index.js index 57c9eb9..d6a3806 100644 --- a/pages/courses/[course]/learn/units/[unit]/index.js +++ b/pages/courses/[course]/learn/units/[unit]/index.js @@ -14,4 +14,12 @@ function CourseDetails() { ) } +export async function getStaticProps(context) { + return { + props: { + namespacesRequired: ['common'], + }, + } +} + export default CourseDetails diff --git a/pages/index.js b/pages/index.js index 3a34012..b01b683 100644 --- a/pages/index.js +++ b/pages/index.js @@ -1,15 +1,17 @@ import MainLayout from '../components/MainLayout' -import Link from 'next/link' +// import Link from 'next/link' import { getPopularTopics } from '../lib/topics' import { getPopularCourses } from '../lib/courses' import _ from 'lodash' +import { Link, withTranslation } from '../i18n' -function Home({ chunkedPopularTopics, chunkedPopularCourses }) { +function Home({ t }) { + console.log(t('title', 'homePage'), t) return (
-

Welkom op het Leer Platform

+

{t('title')}

Leer, ontdek en ontwikkel jouw talent!

@@ -17,105 +19,27 @@ function Home({ chunkedPopularTopics, chunkedPopularCourses }) {
- -
-
- -
-
-

Populaire onderwerpen

- - Bekijk alles - -
-
- - {chunkedPopularTopics.map((topicChunk, index) => ( -
- {topicChunk.map(topic => ( - - ))} -
- ))} - -
-
- -
-
- -
-
-

Populaire cursussen

- - Bekijk alles - -
-
- - {chunkedPopularCourses.map((courseChunk, index) => ( -
- {courseChunk.map(course => ( -
-
-
- -
- - -
-

- - {course.title} - -

-

{ course.description_excerpt }

-
- -
- {course.tags.map(tag => ( - - { tag.name.en } - - ))} -
- -
-
- - - {/* - - {topic.display_name} - - */} -
- ))} -
- ))} - -
-
) } -export async function getStaticProps() { - const popularTopics = await getPopularTopics() - const popularCourses = await getPopularCourses() +// export async function getStaticProps() { +// const popularTopics = await getPopularTopics() +// const popularCourses = await getPopularCourses() - return { - props: { - chunkedPopularTopics: _.chunk(popularTopics, 3), - chunkedPopularCourses: _.chunk(popularCourses, 3), - }, - } -} +// // console.log(popularTopics) + +// return { +// props: { +// namespacesRequired: ['homePage'], +// chunkedPopularTopics: _.chunk(popularTopics, 3), +// chunkedPopularCourses: _.chunk(popularCourses, 3), +// }, +// } +// } + +Home.getInitialProps = async () => ({ + namespacesRequired: ['homePage'], +}) -export default Home +export default withTranslation('homePage')(Home) diff --git a/pages/topics/[topic]/index.js b/pages/topics/[topic]/index.js index 623fb2d..2cb7be4 100644 --- a/pages/topics/[topic]/index.js +++ b/pages/topics/[topic]/index.js @@ -14,4 +14,12 @@ function Topic() { ) } +export async function getStaticProps(context) { + return { + props: { + namespacesRequired: ['common'], + }, + } +} + export default Topic diff --git a/pages/topics/index.js b/pages/topics/index.js index 0239037..52a1904 100644 --- a/pages/topics/index.js +++ b/pages/topics/index.js @@ -10,4 +10,12 @@ function Topics() { ) } +export async function getStaticProps(context) { + return { + props: { + namespacesRequired: ['common'], + }, + } +} + export default Topics diff --git a/public/static/locales/en/common.json b/public/static/locales/en/common.json new file mode 100644 index 0000000..c50161c --- /dev/null +++ b/public/static/locales/en/common.json @@ -0,0 +1,7 @@ +{ + "h1": "A simple example", + "change-locale": "Change locale", + "to-second-page": "To second page", + "error-with-status": "A {{statusCode}} error occurred on server", + "error-without-status": "An error occurred on the server" +} diff --git a/public/static/locales/en/homePage.json b/public/static/locales/en/homePage.json new file mode 100644 index 0000000..12a7785 --- /dev/null +++ b/public/static/locales/en/homePage.json @@ -0,0 +1,4 @@ +{ + "title": "Welcome to the Leer Platform", + "subtitle": "Learn, discover and develop your talent" +} diff --git a/public/static/locales/nl/common.json b/public/static/locales/nl/common.json new file mode 100644 index 0000000..c50161c --- /dev/null +++ b/public/static/locales/nl/common.json @@ -0,0 +1,7 @@ +{ + "h1": "A simple example", + "change-locale": "Change locale", + "to-second-page": "To second page", + "error-with-status": "A {{statusCode}} error occurred on server", + "error-without-status": "An error occurred on the server" +} diff --git a/public/static/locales/nl/homePage.json b/public/static/locales/nl/homePage.json new file mode 100644 index 0000000..53d16de --- /dev/null +++ b/public/static/locales/nl/homePage.json @@ -0,0 +1,4 @@ +{ + "title": "Welkom op het Leer Platform", + "subtitle": "Leer, ontdek en ontwikkel jouw talent" +} diff --git a/server.js b/server.js new file mode 100644 index 0000000..2268be4 --- /dev/null +++ b/server.js @@ -0,0 +1,22 @@ +const express = require('express') +const next = require('next') +const nextI18NextMiddleware = require('next-i18next/middleware').default + +const nextI18next = require('./i18n') + +const port = process.env.PORT || 3000 +const app = next({ dev: process.env.NODE_ENV !== 'production' }) +const handle = app.getRequestHandler(); + +(async () => { + await app.prepare() + const server = express() + + await nextI18next.initPromise + server.use(nextI18NextMiddleware(nextI18next)) + + server.get('*', (req, res) => handle(req, res)) + + await server.listen(port) + console.log(`> Ready on http://localhost:${port}`) // eslint-disable-line no-console +})() diff --git a/pages/catalog/index.js b/temp/catalog/index.js similarity index 67% rename from pages/catalog/index.js rename to temp/catalog/index.js index 2d73f70..c1a0fd0 100644 --- a/pages/catalog/index.js +++ b/temp/catalog/index.js @@ -10,4 +10,12 @@ function Catalog() { ) } +export async function getStaticProps(context) { + return { + props: { + namespacesRequired: ['common'], + }, + } +} + export default Catalog diff --git a/temp/index copy.js b/temp/index copy.js new file mode 100644 index 0000000..88e37b6 --- /dev/null +++ b/temp/index copy.js @@ -0,0 +1,123 @@ +import MainLayout from '../components/MainLayout' +// import Link from 'next/link' +import { getPopularTopics } from '../lib/topics' +import { getPopularCourses } from '../lib/courses' +import _ from 'lodash' +import { Link, withTranslation } from '../i18n' + +function Home({ t, chunkedPopularTopics, chunkedPopularCourses }) { + return ( + +
+
+

Welkom op het Leer Platform

+

Leer, ontdek en ontwikkel jouw talent!

+ + + Bekijk de catalogus + +
+
+ +
+
+ +
+
+

Populaire onderwerpen

+ + Bekijk alles + +
+
+ + {chunkedPopularTopics.map((topicChunk, index) => ( +
+ {topicChunk.map(topic => ( + + ))} +
+ ))} + +
+
+ +
+
+ +
+
+

Populaire cursussen

+ + Bekijk alles + +
+
+ + {chunkedPopularCourses.map((courseChunk, index) => ( +
+ {courseChunk.map(course => ( +
+
+
+ +
+ + +
+

+ + {course.title} + +

+

{ course.description_excerpt }

+
+ +
+ {course.tags.map(tag => ( + + { tag.name.en } + + ))} +
+ +
+
+ + + {/* + + {topic.display_name} + + */} +
+ ))} +
+ ))} + +
+
+
+ ) +} + +export async function getStaticProps() { + const popularTopics = await getPopularTopics() + const popularCourses = await getPopularCourses() + + return { + props: { + chunkedPopularTopics: _.chunk(popularTopics, 3), + chunkedPopularCourses: _.chunk(popularCourses, 3), + namespacesRequired: ['homePage'], + }, + } +} + +export default withTranslation('homePage')(Home) diff --git a/pages/login.js b/temp/login.js similarity index 87% rename from pages/login.js rename to temp/login.js index 35dd54d..8c7ab8c 100644 --- a/pages/login.js +++ b/temp/login.js @@ -1,4 +1,5 @@ import MainLayout from '../components/MainLayout' +import { withTranslation } from '../i18n' function Login() { return ( @@ -33,4 +34,12 @@ function Login() { ) } -export default Login +export async function getStaticProps(context) { + return { + props: { + namespacesRequired: ['common'], + }, + } +} + +export default withTranslation('common')(Login) diff --git a/pages/register.js b/temp/register.js similarity index 67% rename from pages/register.js rename to temp/register.js index a4d40d4..122bf26 100644 --- a/pages/register.js +++ b/temp/register.js @@ -10,4 +10,12 @@ function Register() { ) } +export async function getStaticProps(context) { + return { + props: { + namespacesRequired: ['common'], + }, + } +} + export default Register