feat(localization): add localization for static strings
This commit is contained in:
committed by
Benedikt Rötsch
parent
eaec09a594
commit
68a8052bdf
12
app.js
12
app.js
@@ -11,6 +11,7 @@ const helmet = require('helmet')
|
||||
require('dotenv').config({ path: 'variables.env' })
|
||||
|
||||
const helpers = require('./helpers')
|
||||
const { translate, initializeTranslations } = require('./i18n/i18n')
|
||||
const breadcrumb = require('./lib/breadcrumb')
|
||||
const routes = require('./routes/index')
|
||||
const { initClients, getSpace } = require('./services/contentful')
|
||||
@@ -30,7 +31,6 @@ app.use(bodyParser.json())
|
||||
app.use(bodyParser.urlencoded({ extended: false }))
|
||||
app.use(cookieParser())
|
||||
app.use(express.static(path.join(__dirname, 'public')))
|
||||
app.use(breadcrumb())
|
||||
|
||||
// Force all requests on production to be served over https
|
||||
app.use(function (req, res, next) {
|
||||
@@ -84,11 +84,11 @@ app.use(async function (request, response, next) {
|
||||
const apis = [
|
||||
{
|
||||
id: 'cda',
|
||||
label: 'Delivery (published content)'
|
||||
label: 'Delivery'
|
||||
},
|
||||
{
|
||||
id: 'cpa',
|
||||
label: 'Preview (draft content)'
|
||||
label: 'Preview'
|
||||
}
|
||||
]
|
||||
|
||||
@@ -111,6 +111,10 @@ app.use(async function (request, response, next) {
|
||||
response.locals.currentLocale = defaultLocale
|
||||
}
|
||||
|
||||
// Initialize translations and include them on templates
|
||||
initializeTranslations()
|
||||
response.locals.translate = translate
|
||||
|
||||
// Inject custom helpers
|
||||
response.locals.helpers = helpers
|
||||
|
||||
@@ -123,6 +127,8 @@ app.use(async function (request, response, next) {
|
||||
next()
|
||||
})
|
||||
|
||||
app.use(breadcrumb())
|
||||
|
||||
// Initialize the route handling
|
||||
// Check ./routes/index.js to get a list of all implemented routes
|
||||
app.use('/', routes)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const marked = require('marked')
|
||||
const { translate } = require('./i18n/i18n')
|
||||
|
||||
// Parse markdown text
|
||||
module.exports.markdown = (content = '') => {
|
||||
@@ -11,11 +12,11 @@ module.exports.markdown = (content = '') => {
|
||||
// A handy debugging function we can use to sort of "console.log" our data
|
||||
module.exports.dump = (obj) => JSON.stringify(obj, null, 2)
|
||||
|
||||
module.exports.formatMetaTitle = (title) => {
|
||||
module.exports.formatMetaTitle = (title, localeCode = 'en-US') => {
|
||||
if (!title) {
|
||||
return 'The Example App'
|
||||
return translate('defaultTitle', localeCode)
|
||||
}
|
||||
return `${title.charAt(0).toUpperCase()}${title.slice(1)} — The Example App`
|
||||
return `${title.charAt(0).toUpperCase()}${title.slice(1)} — ${translate('defaultTitle', localeCode)}`
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
46
i18n/i18n.js
Normal file
46
i18n/i18n.js
Normal file
@@ -0,0 +1,46 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
let translations = null
|
||||
// Initializes translation dictionary with contents from /public/locales
|
||||
module.exports.initializeTranslations = () => {
|
||||
if (translations) {
|
||||
return
|
||||
}
|
||||
|
||||
translations = {}
|
||||
|
||||
const localesPath = path.join(__dirname, '..', 'public', 'locales')
|
||||
|
||||
try {
|
||||
const files = fs.readdirSync(localesPath)
|
||||
|
||||
files.forEach((file) => {
|
||||
const localeDict = require(path.join(localesPath, file))
|
||||
translations[file.replace('.json', '')] = localeDict
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error loading localization files:')
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a static string
|
||||
* @param symbol string Identifier for static text
|
||||
* @param locale string Locale code
|
||||
*
|
||||
* @returns string
|
||||
*/
|
||||
module.exports.translate = (symbol, locale = 'en-US') => {
|
||||
const localeDict = translations[locale]
|
||||
if (!localeDict) {
|
||||
return `Localization file for ${locale} is not available`
|
||||
}
|
||||
const translatedValue = localeDict[symbol]
|
||||
if (!translatedValue) {
|
||||
return `Translation not found for ${symbol} in ${locale}`
|
||||
}
|
||||
|
||||
return translatedValue
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
const url = require('url')
|
||||
const { translate } = require('../i18n/i18n')
|
||||
|
||||
module.exports = (modifier) => {
|
||||
return (request, response, next) => {
|
||||
@@ -6,7 +7,10 @@ module.exports = (modifier) => {
|
||||
const urlComponents = url.parse(request.url).pathname.split('/').filter(Boolean)
|
||||
let breadcrumbs = []
|
||||
|
||||
breadcrumbs.push({ label: 'Home', url: baseUrl })
|
||||
breadcrumbs.push({
|
||||
label: translate('homeLabel', response.locals.currentLocale.code),
|
||||
url: baseUrl
|
||||
})
|
||||
// Map components of the path to breadcrumbs with resolvable URLs
|
||||
let mappedComponents = urlComponents.map((component, i, array) => {
|
||||
const path = array.slice(0, i + 1).join('/')
|
||||
|
||||
77
public/locales/de-DE.json
Normal file
77
public/locales/de-DE.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"defaultTitle": "Die Beispielanwendung",
|
||||
"whatIsThisApp": "Was ist die Beispielanwendung?",
|
||||
"metaDescription": "Dies ist die Beispielanwendung, eine Anwendung die Ihnen hilft Ihre eigene Anwendung mit Contentful zu bauen.",
|
||||
"metaTwitterCard": "Dies ist die Beispielanwendung, eine Anwendung die Ihnen hilft Ihre eigene Anwendung mit Contentful zu bauen.",
|
||||
"metaImageAlt": "Dies ist die Beispielanwendung, eine Anwendung die Ihnen hilft Ihre eigene Anwendung mit Contentful zu bauen.",
|
||||
"metaImageDescription": "Dies ist die Beispielanwendung, eine Anwendung die Ihnen hilft Ihre eigene Anwendung mit Contentful zu bauen.",
|
||||
"viewOnGithub": "Auf GitHub ansehen",
|
||||
"apiSwitcherHelp": "Ansehen des veröffentlichten und unveröffentlichten Inhalts durch Wechsel von Delivery und Preview APIs.",
|
||||
"apiLabelHelpcda": "(veröffentlichter Inhalt)",
|
||||
"apiLabelHelpcpa": "(unveröffentlichter Inhalt)",
|
||||
"locale": "Sprache",
|
||||
"localeQuestion": "Sie arbeiten mit verschiedenen Sprachen? Dann können Sie die Sprache für Anfragen an die Content Delivery API definieren.",
|
||||
"settingsLabel": "Einstellungen",
|
||||
"logoAlt": "Die Beispielanwendung für Contentful",
|
||||
"homeLabel": "Home",
|
||||
"coursesLabel": "Kurse",
|
||||
"footerDisclaimer": "Powered by Contentful. Diese Website und deren Materialien existieren nur für Demonstrationszwecken. Sie können diese benutzen, um den Inhalt ihres Contentful Kontos anzusehen.",
|
||||
"imprintLabel": "Impressum",
|
||||
"contactUsLabel": "Uns Kontaktieren",
|
||||
"modalTitle": "Ein referenzierbares Beispiel für Entwickler, die Contentful benutzen.",
|
||||
"modalIntro": "Dies ist die Beispielanwendung, eine Anwendung die Ihnen hilft Ihre eigene Anwendung mit Contentful zu bauen. Sie stellt eine Plattform fürs online Lernen dar, die mithilfe von Contentful gebaut wurde. (sehr meta!)",
|
||||
"modalCodeIntro": "Wenn Sie es bevorzugen, sich die Hände schmutzig zu machen, sehen sie sich die Anwendung hier an",
|
||||
"modalCTALabel": "Gut, verstanden.",
|
||||
"editorialFeaturesHint": "Bearbeiten Sie diesen Eintrag in unserer Web App. Sie müssen sich eingelogged haben und Zugang zum Space haben, um diese Funktion nutzen zu können.",
|
||||
"draftLabel": "Entwurf",
|
||||
"pendingChangesLabel": "Änderungen vorbehalten",
|
||||
"lessonModuleErrorTitle": "⚠️ Ungültiges Lektionsmodul",
|
||||
"lessonModuleErrorBody": "Konnte den Typ nicht erkennen: ",
|
||||
"nextLessonLabel": "Nächste Lektion ansehen",
|
||||
"imageErrorTitle": "⚠️ Bild fehlt",
|
||||
"viewCourseLabel": "Kurs ansehen",
|
||||
"categoriesWelcomeLabel": "Willkommen zur folgenden Kategorie: ",
|
||||
"sitemapWelcomeLabel": "Willkommen zur folgenden Kategorie: ",
|
||||
"tableOfContentsLabel": "Inhalt",
|
||||
"courseOverviewLabel": "Kurs Übersicht",
|
||||
"overviewLabel": "Übersicht",
|
||||
"durationLabel": "Dauer",
|
||||
"minutesLabel": "min",
|
||||
"skillLevelLabel": "Komplexität",
|
||||
"startCourseLabel": "Kurs beginnen",
|
||||
"categoriesLabel": "Kategorien",
|
||||
"allCoursesLabel": "Alle Kurse",
|
||||
"somethingWentWrongLabel": "Hmm, etwas ging schief.",
|
||||
"tryLabel": "Versuchen Sie",
|
||||
"contentModelChangedErrorLabel": "Überprüfen Sie, ob das Content Model verändert wurde.",
|
||||
"draftOrPublishedErrorLabel": "Überprüfen Sie, ob es nicht veröffentlichte Änderungen gibt.",
|
||||
"localeContentErrorLabel": "Überprüfen Sie, ob es Inhalt für diese Sprache gibt.",
|
||||
"verifyCredentialsErrorLabel": "Überprüfen Sie, ob die Zugangsdaten richtig und nicht abgelaufen sind.",
|
||||
"stackTraceErrorLabel": "Schauen Sie sich den folgenden Stack Trace an",
|
||||
"errorLabel": "Fehler",
|
||||
"stackTraceLabel": "Stack Trace",
|
||||
"companyLabel": "Firma",
|
||||
"officeLabel": "Büro in Berlin",
|
||||
"germanyLabel": "Deutschland",
|
||||
"registrationCourtLabel": "Amtsgericht",
|
||||
"managingDirectorLabel": "Verwalter",
|
||||
"vatNumberLabel": "Steuernummer",
|
||||
"settingsIntroLabel": "Um Inhalt von unseren APIs zu bekommen, müssen Anwendungen von Kunden sich authentifizieren, sowohl mit der Space ID als auch dem Access Token.",
|
||||
"changesSavedLabel": "Änderungen erfolgreich gespeichert!",
|
||||
"errorOcurredTitleLabel": "Fehler aufgetreten",
|
||||
"errorOcurredMessageLabel": "Einige Fehler sind aufgetreten. Bitte schauen Sie sich die Fehlermeldungen neben den Feldern an.",
|
||||
"connectedToSpaceLabel": "Mit einem Space verbinden.",
|
||||
"spaceIdLabel": "Space ID",
|
||||
"spaceIdHelpText": "Die Space Id ist eine eindeutige Identifizierung für Ihren Space.",
|
||||
"accessTokenLabel": "Access Token",
|
||||
"contentDeliveryApiHelpText": "Schauen Sie sich veröffentlichten Inhalt mit dieser API an.",
|
||||
"contentPreviewApiHelpText": "Schauen Sie sich unveröffentlichten Inhalt mit dieser API an. (z.B. Inhalt im Zustand “Entwurf”).",
|
||||
"enableEditorialFeaturesLabel": "Editoriale Funktionen aktivieren.",
|
||||
"enableEditorialFeaturesHelpText": "Aktivieren, um Bearbeitung und weitere kontextabhängige Helferlein zu aktivieren. Damit dies funktioniert, müssen sie Zugang zu dem Space haben.",
|
||||
"saveSettingsButtonLabel": "Einstellungen Speichern",
|
||||
"fieldIsRequiredLabel": "Diese Feld ist notwendig.",
|
||||
"deliveryKeyInvalidLabel": "Ihr Delivery API Zugangsschlüssel ist ungültig.",
|
||||
"spaceOrTokenInvalid": "Dieser Space existiert nicht, oder Ihr Access Token kommt nicht von diesem Space.",
|
||||
"somethingWentWrongLabel": "Irgendetwas lief falsch.",
|
||||
"previewKeyInvalidLabel": "Ihr Preview API Zugangsschlüssel ist ungültig."
|
||||
}
|
||||
77
public/locales/en-US.json
Normal file
77
public/locales/en-US.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"defaultTitle": "The Example App",
|
||||
"whatIsThisApp": "What is this example app?",
|
||||
"metaDescription": "This is The Example App, an application built to serve you as a reference while building your own applications using Contentful.",
|
||||
"metaTwitterCard": "This is The Example App, an application built to serve you as a reference while building your own applications using Contentful.",
|
||||
"metaImageAlt": "This is The Example App, an application built to serve you as a reference while building your own applications using Contentful.",
|
||||
"metaImageDescription": "This is The Example App, an application built to serve you as a reference while building your own applications using Contentful.",
|
||||
"viewOnGithub": "View on Github",
|
||||
"apiSwitcherHelp": "View the published or draft content by simply switching between the Deliver and Preview APIs.",
|
||||
"apiLabelHelpcda": "(published content)",
|
||||
"apiLabelHelpcpa": "(draft content)",
|
||||
"locale": "Locale",
|
||||
"localeQuestion": "Working with multiple languages? You can query the Content Delivery API for a specific locale.",
|
||||
"settingsLabel": "Settings",
|
||||
"logoAlt": "Contentful Example App",
|
||||
"homeLabel": "Home",
|
||||
"coursesLabel": "Courses",
|
||||
"footerDisclaimer": "Powered by Contentful. This website and the materials found on it are for demo purposes. You can use this to preview the content created on your Contentful account.",
|
||||
"imprintLabel": "Imprint",
|
||||
"contactUsLabel": "Contact us",
|
||||
"modalTitle": "A referenceable example for developers using Contentful",
|
||||
"modalIntro": "This is The Example App, an application built to serve you as a reference while building your own applications using Contentful. This app is an online learning platform which teaches you how Contentful was used to build this app (so meta)!",
|
||||
"modalCodeIntro": "If you prefer to start by getting your hands dirty with code, check out this app on",
|
||||
"modalCTALabel": "Ok, got it.",
|
||||
"editorialFeaturesHint": "Edit this entry in our web app. You have to be logged in and have access to the connected space to use this feature.",
|
||||
"draftLabel": "draft",
|
||||
"pendingChangesLabel": "pending changes",
|
||||
"lessonModuleErrorTitle": "⚠️ Invalid lesson module",
|
||||
"lessonModuleErrorBody": "Could not determine type of",
|
||||
"nextLessonLabel": "View next lesson",
|
||||
"imageErrorTitle": "⚠️ Image missing",
|
||||
"viewCourseLabel": "view course",
|
||||
"categoriesWelcomeLabel": "Welcome to",
|
||||
"sitemapWelcomeLabel": "Welcome to",
|
||||
"tableOfContentsLabel": "Table of contents",
|
||||
"courseOverviewLabel": "Cource overview",
|
||||
"overviewLabel": "Overview",
|
||||
"durationLabel": "Duration",
|
||||
"minutesLabel": "min",
|
||||
"skillLevelLabel": "Skill level",
|
||||
"startCourseLabel": "Start course",
|
||||
"categoriesLabel": "Categories",
|
||||
"allCoursesLabel": "All courses",
|
||||
"somethingWentWrongLabel": "Oops Something went wrong",
|
||||
"tryLabel": "Try",
|
||||
"contentModelChangedErrorLabel": "Check if the content model has changed",
|
||||
"draftOrPublishedErrorLabel": "Check the selection has content in draft or published state (for Preview or Delivery)",
|
||||
"localeContentErrorLabel": "Check if there's any content for this locale",
|
||||
"verifyCredentialsErrorLabel": "Verify credentials are correct and up to date",
|
||||
"stackTraceErrorLabel": "Check the stack trace below",
|
||||
"errorLabel": "Error",
|
||||
"stackTraceLabel": "Stack trace",
|
||||
"companyLabel": "Company",
|
||||
"officeLabel": "Office Berlin",
|
||||
"germanyLabel": "Germany",
|
||||
"registrationCourtLabel": "Registration Court",
|
||||
"managingDirectorLabel": "Managing Director",
|
||||
"vatNumberLabel": "VAT Number",
|
||||
"settingsIntroLabel": "To query and get content using the APIs, client applications need to authenticate with both the Space ID and an access token.",
|
||||
"changesSavedLabel": "Changes saved successfully!",
|
||||
"errorOcurredTitleLabel": "Error occurred",
|
||||
"errorOcurredMessageLabel": "Some errors occurred. Please check the error messages next to the fields.",
|
||||
"connectedToSpaceLabel": "Connected to space",
|
||||
"spaceIdLabel": "Space ID",
|
||||
"spaceIdHelpText": "The Space ID is a unique identifier for your space.",
|
||||
"accessTokenLabel": "access token",
|
||||
"contentDeliveryApiHelpText": "View published content using this API.",
|
||||
"contentPreviewApiHelpText": "Preview unpublished content using this API (i.e. content with “Draft” status).",
|
||||
"enableEditorialFeaturesLabel": "Enable editorial features",
|
||||
"enableEditorialFeaturesHelpText": "Enable to display an edit link and other contextual helpers for authors. You need to have access to the connected space to make this work.",
|
||||
"saveSettingsButtonLabel": "Save settings",
|
||||
"fieldIsRequiredLabel": "This field is required",
|
||||
"deliveryKeyInvalidLabel": "Your Delivery API key is invalid.",
|
||||
"spaceOrTokenInvalid": "This space does not exist or your access token is not associated with your space.",
|
||||
"somethingWentWrongLabel": "Something went wrong",
|
||||
"previewKeyInvalidLabel": "Your Preview API key is invalid."
|
||||
}
|
||||
@@ -11,6 +11,7 @@ const {
|
||||
|
||||
const attachEntryState = require('../lib/entry-state')
|
||||
const { updateCookie } = require('../lib/cookies')
|
||||
const { translate } = require('../i18n/i18n')
|
||||
|
||||
/**
|
||||
* Renders courses list when `/courses` route is requested
|
||||
@@ -33,7 +34,11 @@ module.exports.getCourses = async (request, response, next) => {
|
||||
}
|
||||
|
||||
categories = await getCategories(response.locals.currentLocale.code, response.locals.currentApi.id)
|
||||
response.render('courses', { title: `All Courses (${courses.length})`, categories, courses })
|
||||
response.render('courses', {
|
||||
title: `${translate('allCoursesLabel', response.locals.currentLocale.code)} (${courses.length})`,
|
||||
categories,
|
||||
courses
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const { translate } = require('../i18n/i18n')
|
||||
/**
|
||||
* Renders imprint page when `/imprint` route is requested
|
||||
* @param request - Object - Express request
|
||||
@@ -6,6 +7,7 @@
|
||||
* @returns {undefined}
|
||||
*/
|
||||
module.exports.getImprint = (request, response, next) => {
|
||||
response.render('imprint', { title: 'Imprint' })
|
||||
response.render('imprint', {
|
||||
title: translate('imprintLabel', response.locals.currentLocale.code)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -33,4 +33,3 @@ module.exports.getLandingPage = async (request, response, next) => {
|
||||
|
||||
response.render('landingPage', { title: pathname, landingPage })
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
const { createClient } = require('contentful')
|
||||
const { initClients, getSpace } = require('./../services/contentful')
|
||||
const { updateCookie } = require('../lib/cookies')
|
||||
const { translate } = require('../i18n/i18n')
|
||||
|
||||
const SETTINGS_NAME = 'theExampleAppSettings'
|
||||
|
||||
@@ -20,7 +21,7 @@ async function renderSettings (response, opts) {
|
||||
}
|
||||
|
||||
response.render('settings', {
|
||||
title: 'Settings',
|
||||
title: translate('settingsLabel', response.locals.currentLocale.code),
|
||||
errors: {},
|
||||
hasErrors: false,
|
||||
success: false,
|
||||
@@ -56,6 +57,7 @@ module.exports.getSettings = async (request, response, next) => {
|
||||
* @returns {undefined}
|
||||
*/
|
||||
module.exports.postSettings = async (request, response, next) => {
|
||||
const currentLocale = response.locals.currentLocale
|
||||
const errorList = []
|
||||
const { spaceId, deliveryToken, previewToken, editorialFeatures } = request.body
|
||||
const settings = {
|
||||
@@ -69,21 +71,21 @@ module.exports.postSettings = async (request, response, next) => {
|
||||
if (!spaceId) {
|
||||
errorList.push({
|
||||
field: 'spaceId',
|
||||
message: 'This field is required'
|
||||
message: translate('fieldIsRequiredLabel', currentLocale.code)
|
||||
})
|
||||
}
|
||||
|
||||
if (!deliveryToken) {
|
||||
errorList.push({
|
||||
field: 'deliveryToken',
|
||||
message: 'This field is required'
|
||||
message: translate('fieldIsRequiredLabel', currentLocale.code)
|
||||
})
|
||||
}
|
||||
|
||||
if (!previewToken) {
|
||||
errorList.push({
|
||||
field: 'previewToken',
|
||||
message: 'This field is required'
|
||||
message: translate('fieldIsRequiredLabel', currentLocale.code)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -98,17 +100,17 @@ module.exports.postSettings = async (request, response, next) => {
|
||||
if (err.response.status === 401) {
|
||||
errorList.push({
|
||||
field: 'deliveryToken',
|
||||
message: 'Your Delivery API key is invalid.'
|
||||
message: translate('deliveryKeyInvalidLabel', currentLocale.code)
|
||||
})
|
||||
} else if (err.response.status === 404) {
|
||||
errorList.push({
|
||||
field: 'spaceId',
|
||||
message: 'This space does not exist or your access token is not associated with your space.'
|
||||
message: translate('spaceOrTokenInvalid', currentLocale.code)
|
||||
})
|
||||
} else {
|
||||
errorList.push({
|
||||
field: 'deliveryToken',
|
||||
message: `Something went wrong: ${err.response.data.message}`
|
||||
message: `${translate('somethingWentWrongLabel', currentLocale.code)}: ${err.response.data.message}`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -126,17 +128,17 @@ module.exports.postSettings = async (request, response, next) => {
|
||||
if (err.response.status === 401) {
|
||||
errorList.push({
|
||||
field: 'previewToken',
|
||||
message: 'Your Preview API key is invalid.'
|
||||
message: translate('previewKeyInvalidLabel', currentLocale.code)
|
||||
})
|
||||
} else if (err.response.status === 404) {
|
||||
errorList.push({
|
||||
field: 'spaceId',
|
||||
message: 'This space does not exist or your delivery token is not associated with your space.'
|
||||
message: translate('spaceOrTokenInvalid', currentLocale.code)
|
||||
})
|
||||
} else {
|
||||
errorList.push({
|
||||
field: 'previewToken',
|
||||
message: `Something went wrong: ${err.response.data.message}`
|
||||
message: `${translate('somethingWentWrongLabel', currentLocale.code)}: ${err.response.data.message}`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -171,4 +173,3 @@ module.exports.postSettings = async (request, response, next) => {
|
||||
success: errorList.length === 0
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ describe('courses', () => {
|
||||
return request(app).get('/courses')
|
||||
.expect(200)
|
||||
.then((response) => {
|
||||
expect(response.text.match(/<h1>All Courses /)).toBeTruthy()
|
||||
expect(response.text.match(/<h1>All courses /)).toBeTruthy()
|
||||
})
|
||||
})
|
||||
test('it should render a course', () => {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
const { getCourses, getCourse, getCoursesByCategory, getLesson } = require('../../routes/courses')
|
||||
const { getSettings } = require('../../routes/settings')
|
||||
const { mockCourse, mockCategory } = require('./mocks/index')
|
||||
const { translate, initializeTranslations } = require('../../i18n/i18n')
|
||||
|
||||
jest.mock('../../services/contentful')
|
||||
const contentful = require('../../services/contentful')
|
||||
@@ -25,6 +26,8 @@ const response = {
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
initializeTranslations()
|
||||
|
||||
contentful.getCourses.mockImplementation(() => [mockCourse])
|
||||
contentful.getCourse.mockImplementation(() => mockCourse)
|
||||
|
||||
@@ -45,7 +48,7 @@ describe('Courses', () => {
|
||||
test('it should courses list once', async () => {
|
||||
await getCourses(request, response)
|
||||
expect(response.render.mock.calls[0][0]).toBe('courses')
|
||||
expect(response.render.mock.calls[0][1].title).toBe('All Courses (1)')
|
||||
expect(response.render.mock.calls[0][1].title).toBe('All courses (1)')
|
||||
expect(response.render.mock.calls[0][1].courses.length).toBe(1)
|
||||
expect(response.render.mock.calls.length).toBe(1)
|
||||
})
|
||||
@@ -88,3 +91,17 @@ describe('Settings', () => {
|
||||
expect(response.render.mock.calls[0][1].settings).toBe(response.locals.settings)
|
||||
})
|
||||
})
|
||||
|
||||
describe('i18n', () => {
|
||||
test('It returns an error when locale file is not found', () => {
|
||||
expect(translate('foo', 'bar-locale')).toBe('Localization file for bar-locale is not available')
|
||||
})
|
||||
|
||||
test('It returns an error when symbol is not found on locale file', () => {
|
||||
expect(translate('foo', 'en-US')).toBe('Translation not found for foo in en-US')
|
||||
})
|
||||
|
||||
test('It returns the translated string when symbol is found on locale file', () => {
|
||||
expect(translate('coursesLabel', 'en-US')).toBe('Courses')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -10,12 +10,12 @@ block content
|
||||
.layout-sidebar
|
||||
section.layout-sidebar__sidebar
|
||||
.layout-sidebar__sidebar-header
|
||||
h2.layout-sidebar__sidebar-title Table of contents
|
||||
h2.layout-sidebar__sidebar-title #{translate('tableOfContentsLabel', currentLocale.code)}
|
||||
.layout-sidebar__sidebar-content
|
||||
.table-of-contents
|
||||
.table-of-contents__list
|
||||
.table-of-contents__item
|
||||
a.table-of-contents__link(href=`/courses/${course.fields.slug}${queryString}` class=(currentPath.endsWith(course.fields.slug) ? 'active' : '') class=(visitedLessons.includes(course.sys.id) ? 'visited' : '')) Course overview
|
||||
a.table-of-contents__link(href=`/courses/${course.fields.slug}${queryString}` class=(currentPath.endsWith(course.fields.slug) ? 'active' : '') class=(visitedLessons.includes(course.sys.id) ? 'visited' : '')) #{translate('courseOverviewLabel', currentLocale.code)}
|
||||
each l in course.fields.lessons
|
||||
if l.fields
|
||||
.table-of-contents__item
|
||||
@@ -28,17 +28,17 @@ block content
|
||||
h1.course__title= course.fields.title
|
||||
+editorialFeatures(course)
|
||||
.course__overview
|
||||
h3.course__overview-title Overview
|
||||
h3.course__overview-title #{translate('overviewLabel', currentLocale.code)}
|
||||
if course.fields.duration
|
||||
.course__overview-item
|
||||
svg.course__overview-icon
|
||||
use(xlink:href='/icons/icons.svg#duration')
|
||||
.course__overview-value Duration: #{course.fields.duration} min
|
||||
.course__overview-value #{translate('durationLabel', currentLocale.code)}: #{course.fields.duration} #{translate('minutesLabel', currentLocale.code)}
|
||||
if course.fields.skillLevel
|
||||
.course__overview-item
|
||||
svg.course__overview-icon
|
||||
use(xlink:href='/icons/icons.svg#skill-level')
|
||||
.course__overview-value Skill level: #{course.fields.skillLevel}
|
||||
.course__overview-value #{translate('skillLevelLabel', currentLocale.code)}: #{course.fields.skillLevel}
|
||||
.course__overview-cta-wrapper
|
||||
a.course__overview-cta.cta(href=`/courses/${course.fields.slug}/lessons/${course.fields.lessons[0].fields.slug}${queryString}`) Start course
|
||||
a.course__overview-cta.cta(href=`/courses/${course.fields.slug}/lessons/${course.fields.lessons[0].fields.slug}${queryString}`) #{translate('startCourseLabel', currentLocale.code)}
|
||||
.course__description !{helpers.markdown(course.fields.description)}
|
||||
|
||||
@@ -9,12 +9,12 @@ block content
|
||||
.layout-sidebar
|
||||
section.layout-sidebar__sidebar
|
||||
.layout-sidebar__sidebar-header
|
||||
h2.layout-sidebar__sidebar-title Categories
|
||||
h2.layout-sidebar__sidebar-title #{translate('categoriesLabel', currentLocale.code)}
|
||||
.layout-sidebar__sidebar-content
|
||||
.sidebar-menu
|
||||
ul.sidebar-menu__list
|
||||
li.sidebar-menu__item
|
||||
a.sidebar-menu__link(href=`/courses${queryString}` class=(currentPath.endsWith('/courses') ? 'active' : '')) All courses
|
||||
a.sidebar-menu__link(href=`/courses${queryString}` class=(currentPath.endsWith('/courses') ? 'active' : '')) #{translate('allCoursesLabel', currentLocale.code)}
|
||||
each category in categories
|
||||
li.sidebar-menu__item
|
||||
a.sidebar-menu__link(href=`/courses/categories/${category.fields.slug}${queryString}` class=(currentPath.endsWith(category.fields.slug) ? 'active' : '')) #{category.fields.title}
|
||||
|
||||
@@ -6,18 +6,18 @@ block content
|
||||
.layout-centered
|
||||
+breadcrumb
|
||||
.error
|
||||
h1 Oops Something went wrong (#{error.status})
|
||||
h2 Try:
|
||||
h1 #{translate('somethingWentWrongLabel', currentLocale.code)} (#{error.status})
|
||||
h2 #{translate('tryLabel', currentLocale.code)}:
|
||||
ul
|
||||
li Check if the content model has changed
|
||||
li Check the selection has content in draft or published state (for Preview or Delivery)
|
||||
li Check if there's any content for this locale
|
||||
li Verify credentials are correct and up to date
|
||||
li Check the stack trace below
|
||||
li #{translate('contentModelChangedErrorLabel', currentLocale.code)}
|
||||
li #{translate('draftOrPublishedErrorLabel', currentLocale.code)}
|
||||
li #{translate('localeContentErrorLabel', currentLocale.code)}
|
||||
li #{translate('verifyCredentialsErrorLabel', currentLocale.code)}
|
||||
li #{translate('stackTraceErrorLabel', currentLocale.code)}
|
||||
if error.response
|
||||
h2 Error
|
||||
h2 #{translate('errorLabel', currentLocale.code)}
|
||||
pre.error__stack-trace
|
||||
code.shell #{helpers.dump(error.response.data)}
|
||||
h2 Stack trace
|
||||
h2 #{translate('stackTraceLabel', currentLocale.code)}
|
||||
pre.error__stack-trace
|
||||
code.shell #{error.stack}
|
||||
|
||||
@@ -13,22 +13,22 @@ block content
|
||||
table
|
||||
tbody
|
||||
tr
|
||||
th Company:
|
||||
th #{translate('companyLabel', currentLocale.code)}:
|
||||
td Contentful GmbH
|
||||
tr
|
||||
th Office Berlin:
|
||||
th #{translate('officeLabel', currentLocale.code)}:
|
||||
td
|
||||
| Ritterstr. 12-14
|
||||
br
|
||||
| 10969 Berlin
|
||||
br
|
||||
| Germany
|
||||
| #{translate('germanyLabel', currentLocale.code)}
|
||||
tr
|
||||
th Registration Court:
|
||||
th #{translate('registrationCourtLabel', currentLocale.code)}:
|
||||
td Berlin-Charlottenburg HRB 155607 B
|
||||
tr
|
||||
th Managing Director:
|
||||
th #{translate('managingDirectorLabel', currentLocale.code)}:
|
||||
td Sascha Konietzke
|
||||
tr
|
||||
th VAT Number:
|
||||
th #{translate('vatNumberLabel', currentLocale.code)}:
|
||||
td DE275148225
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
title= helpers.formatMetaTitle(title)
|
||||
title= helpers.formatMetaTitle(title, currentLocale.code)
|
||||
link(rel='stylesheet', href='/stylesheets/style.css')
|
||||
meta(name='viewport' content='width=device-width, initial-scale=1')
|
||||
meta(name='description' content='This is The Example App, an application built to serve you as a reference while building your own applications using Contentful.')
|
||||
meta(name='twitter:card' content='This is The Example App, an application built to serve you as a reference while building your own applications using Contentful.')
|
||||
meta(property='og:title' content=helpers.formatMetaTitle(title))
|
||||
meta(name='description' content=translate('metaDescription', currentLocale.code))
|
||||
meta(name='twitter:card' content=translate('metaTwitterCard', currentLocale.code))
|
||||
meta(property='og:title' content=helpers.formatMetaTitle(title, currentLocale.code))
|
||||
meta(property='og:type' content='article')
|
||||
meta(property='og:url' content=`http://contentful-example-app.herokuapp.com${currentPath}`)
|
||||
meta(property='og:image' content='http://contentful-example-app.herokuapp.com/og-image.jpg')
|
||||
meta(property='og:image:type' content='image/jpeg')
|
||||
meta(property='og:image:width' content='1200')
|
||||
meta(property='og:image:height' content='1200')
|
||||
meta(property='og:image:alt' content='This is The Example App, an application built to serve you as a reference while building your own applications using Contentful.')
|
||||
meta(property='og:description' content='This is The Example App, an application built to serve you as a reference while building your own applications using Contentful.')
|
||||
meta(property='og:image:alt' content=translate('metaImageAlt', currentLocale.code))
|
||||
meta(property='og:description' content=translate('metaImageDescription', currentLocale.code))
|
||||
link(rel='apple-touch-icon' sizes='120x120' href='/apple-touch-icon.png')
|
||||
link(rel='icon' type='image/png' sizes='32x32' href='/favicon-32x32.png')
|
||||
link(rel='icon' type='image/png' sizes='16x16' href='/favicon-16x16.png')
|
||||
@@ -31,55 +31,55 @@ html
|
||||
a#about-this-modal-trigger(href='#').header__title
|
||||
svg.course__overview-icon
|
||||
use(xlink:href='/icons/icons.svg#info')
|
||||
span What is this example app?
|
||||
span #{translate('whatIsThisApp', currentLocale.code)}
|
||||
.header__upper-second
|
||||
.header__upper-copy
|
||||
a.header__upper-link(href='https://images.contentful.com/82t39nctsu20/1JOkYZnY8YG0w88ImweME2/c8aef71dfe1ea633e16e17d99379416c/Github-repo_2x__1_.png' target='_blank' rel='noopener')
|
||||
svg.header__upper-icon
|
||||
use(xlink:href='/icons/icons.svg#github')
|
||||
| View on Github
|
||||
| #{translate('viewOnGithub', currentLocale.code)}
|
||||
|
||||
.header__controls
|
||||
.header__controls_group
|
||||
form(action='' method='get')
|
||||
.header__controls_label API: #{currentApi.label}
|
||||
.header__controls_label API: #{currentApi.label} #{translate(`apiLabelHelp${currentApi.id}`, currentLocale.code)}
|
||||
.header__controls_dropdown
|
||||
.header__controls_help_text View the published or draft content by simply switching between the Deliver and Preview APIs.
|
||||
.header__controls_help_text #{translate('apiSwitcherHelp', currentLocale.code)}
|
||||
button.header__controls_button(
|
||||
type='submit'
|
||||
name='api'
|
||||
value='cda'
|
||||
class=`${currentApi.id === 'cda' ? 'header__controls_button--active' : ''}`
|
||||
) Delivery (published content)
|
||||
) Delivery #{translate('apiLabelHelpcda', currentLocale.code)}
|
||||
button.header__controls_button(
|
||||
type='submit'
|
||||
name='api'
|
||||
value='cpa'
|
||||
class=`${currentApi.id === 'cpa' ? 'header__controls_button--active' : ''}`
|
||||
) Preview (draft content)
|
||||
) Preview #{translate('apiLabelHelpcpa', currentLocale.code)}
|
||||
input(type='hidden' name='locale' value=currentLocale.code)
|
||||
|
||||
.header__controls_group
|
||||
form(action='' method='get')
|
||||
input(type='hidden' name='api' value=currentApi.id)
|
||||
.header__controls_label Locale: #{currentLocale.name}
|
||||
.header__controls_label #{translate('locale', currentLocale.code)}: #{currentLocale.name}
|
||||
.header__controls_dropdown
|
||||
.header__controls_help_text Working with multiple languages? You can query the Content Delivery API for a specific locale.
|
||||
.header__controls_help_text #{translate('localeQuestion', currentLocale.code)}
|
||||
each locale in locales
|
||||
button.header__controls_button(type='submit' name='locale' value=locale.code class=`${locale.code === currentLocale.code ? 'header__controls_button--active' : ''}`)= `${locale.name} (${locale.code})`
|
||||
.header__upper-menu
|
||||
a(href=`/settings${queryString}` class=(currentPath.startsWith('/settings') ? 'active' : '')) Settings
|
||||
a(href=`/settings${queryString}` class=(currentPath.startsWith('/settings') ? 'active' : '')) #{translate('settingsLabel', currentLocale.code)}
|
||||
.header__lower-wrapper
|
||||
.header__lower.layout-centered
|
||||
.header__logo
|
||||
a.header__logo-link(href=`/${queryString}`)
|
||||
img(src='/images/logo-node.svg' alt='Contentful Example App')
|
||||
img(src='/images/logo-node.svg' alt=translate('logoAlt', currentLocale.code))
|
||||
nav.header__navigation.main-navigation
|
||||
ul
|
||||
li
|
||||
a(href=`/${queryString}` class=(currentPath === '/'? 'active' : '')) Home
|
||||
a(href=`/${queryString}` class=(currentPath === '/'? 'active' : '')) #{translate('homeLabel', currentLocale.code)}
|
||||
li
|
||||
a(href=`/courses${queryString}` class=(currentPath.startsWith('/courses') ? 'active' : '') ) Courses
|
||||
a(href=`/courses${queryString}` class=(currentPath.startsWith('/courses') ? 'active' : '') ) #{translate('coursesLabel', currentLocale.code)}
|
||||
.main__content
|
||||
block content
|
||||
|
||||
@@ -90,9 +90,9 @@ html
|
||||
nav.footer__navigation.main-navigation
|
||||
ul
|
||||
li
|
||||
a(href=`/${queryString}` class=(currentPath === '/'? 'active' : '')) Home
|
||||
a(href=`/${queryString}` class=(currentPath === '/'? 'active' : '')) #{translate('homeLabel', currentLocale.code)}
|
||||
li
|
||||
a(href=`/courses${queryString}` class=(currentPath.startsWith('/courses') ? 'active' : '') ) Courses
|
||||
a(href=`/courses${queryString}` class=(currentPath.startsWith('/courses') ? 'active' : '') ) #{translate('coursesLabel', currentLocale.code)}
|
||||
.footer__apps
|
||||
//- a(href='#')
|
||||
//- img(src='/images/badge-app-store.svg')
|
||||
@@ -103,12 +103,12 @@ html
|
||||
a(href='https://www.contentful.com/' target='_blank' rel='noopener')
|
||||
img.footer__disclaimer-logo(src='/images/contentful-logo.svg')
|
||||
p.footer__disclaimer-text
|
||||
| Powered by Contentful. This website and the materials found on it are for demo purposes. You can use this to preview the content created on your Contentful account.
|
||||
a(href='https://images.contentful.com/82t39nctsu20/1JOkYZnY8YG0w88ImweME2/c8aef71dfe1ea633e16e17d99379416c/Github-repo_2x__1_.png' target='_blank' rel='noopener') View on Github
|
||||
| #{translate('footerDisclaimer', currentLocale.code)}
|
||||
a(href='https://images.contentful.com/82t39nctsu20/1JOkYZnY8YG0w88ImweME2/c8aef71dfe1ea633e16e17d99379416c/Github-repo_2x__1_.png' target='_blank' rel='noopener') #{translate('viewOnGithub', currentLocale.code)}
|
||||
| .
|
||||
a(href=`/imprint${queryString}` ) Imprint
|
||||
a(href=`/imprint${queryString}` ) #{translate('imprintLabel', currentLocale.code)}
|
||||
| .
|
||||
a(href=`https://www.contentful.com/contact/` ) Contact us
|
||||
a(href=`https://www.contentful.com/contact/` ) #{translate('contactUsLabel', currentLocale.code)}
|
||||
| .
|
||||
.footer__social
|
||||
p
|
||||
@@ -124,15 +124,15 @@ html
|
||||
section.modal#about-this-modal
|
||||
.modal__overlay.close
|
||||
.modal__wrapper
|
||||
h1.modal__title A referenceable example for developers using Contentful
|
||||
h1.modal__title #{translate('modalTitle', currentLocale.code)}
|
||||
.modal__content
|
||||
p This is The Example App, an application built to serve you as a reference while building your own applications using Contentful. This app is an online learning platform which teaches you how Contentful was used to build this app (so meta)!
|
||||
p #{translate('modalIntro', currentLocale.code)}
|
||||
p
|
||||
| If you prefer to start by getting your hands dirty with code, check out this app on
|
||||
| #{translate('modalCodeIntro', currentLocale.code)}
|
||||
a(href='https://images.contentful.com/82t39nctsu20/1JOkYZnY8YG0w88ImweME2/c8aef71dfe1ea633e16e17d99379416c/Github-repo_2x__1_.png' target='_blank' rel='noopener') Github
|
||||
| .
|
||||
.modal__cta-wrapper
|
||||
a(href='#').modal__cta.close Ok, got it.
|
||||
a(href='#').modal__cta.close #{translate('modalCTALabel', currentLocale.code)}
|
||||
.modal__close-wrapper
|
||||
a(href='#').modal__close-button.close
|
||||
svg
|
||||
|
||||
@@ -13,5 +13,4 @@ mixin courseCard(course = {fields: {title: '', description: '', categories: [],
|
||||
+entryState(course)
|
||||
p.course-card__description= course.fields.shortDescription
|
||||
.course-card__link-wrapper
|
||||
a.course-card__link(href=`/courses/${course.fields.slug}${queryString}`) view course
|
||||
|
||||
a.course-card__link(href=`/courses/${course.fields.slug}${queryString}`) #{translate("viewCourseLabel", currentLocale.code)}
|
||||
|
||||
@@ -15,4 +15,4 @@ mixin editorialFeatures(entry)
|
||||
.editorial-features__hint-wrapper
|
||||
svg.editorial-features__hint-icon
|
||||
use(xlink:href='/icons/icons.svg#info')
|
||||
.editorial-features__hint-message Edit this entry in our web app. You have to be logged in and have access to the connected space to use this feature.
|
||||
.editorial-features__hint-message #{translate('editorialFeaturesHint', currentLocale.code)}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mixin entryState(entry)
|
||||
if entry.draft
|
||||
.pill.pill--draft draft
|
||||
.pill.pill--draft #{translate('draftLabel', currentLocale.code)}
|
||||
if entry.pendingChanges
|
||||
.pill.pill--pending-changes pending changes
|
||||
.pill.pill--pending-changes #{translate('pendingChangesLabel', currentLocale.code)}
|
||||
|
||||
@@ -20,10 +20,10 @@ mixin lesson(lesson, course, nextLesson)
|
||||
when 'lessonImage'
|
||||
+lessonModuleImage(module)
|
||||
else
|
||||
h2 ️️⚠️ Invalid lesson module
|
||||
h2 ️️#{translate('lessonModuleErrorTitle', currentLocale.code)}
|
||||
p
|
||||
span Could not determine type of
|
||||
span #{translate('lessonModuleErrorBody', currentLocale.code)}
|
||||
strong #{module.sys.id}
|
||||
if nextLesson
|
||||
a.lesson__cta.cta(href=`/courses/${course.fields.slug}/lessons/${nextLesson.fields.slug}${queryString}`) View next lesson
|
||||
a.lesson__cta.cta(href=`/courses/${course.fields.slug}/lessons/${nextLesson.fields.slug}${queryString}`) #{translate('nextLessonLabel', currentLocale.code)}
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@ mixin lessonModuleImage(module)
|
||||
if module.fields.image && module.fields.image.fields.file && module.fields.image.fields.file.url
|
||||
img.lesson-module-image__image(src=module.fields.image.fields.file.url alt=module.fields.image.fields.title)
|
||||
else
|
||||
h3 ⚠️ Image missing
|
||||
h3 #{translate('imageErrorTitle', currentLocale.code)}
|
||||
|
||||
@@ -14,4 +14,4 @@ mixin moduleHighlightedCourse(module, course)
|
||||
.module-higlighted-course__description-wrapper
|
||||
p !{helpers.markdown(course.fields.shortDescription)}
|
||||
.module-higlighted-course__link-wrapper
|
||||
a.module-higlighted-course__link(href=`/courses/${course.fields.slug}${queryString}`) view course
|
||||
a.module-higlighted-course__link(href=`/courses/${course.fields.slug}${queryString}`) #{translate('viewCourseLabel', currentLocale.code)}
|
||||
|
||||
@@ -13,60 +13,60 @@ block content
|
||||
.layout-centered-small
|
||||
+breadcrumb
|
||||
h1= title
|
||||
p To query and get content using the APIs, client applications need to authenticate with both the Space ID and an access token.
|
||||
p #{translate('settingsIntroLabel', currentLocale.code)}
|
||||
|
||||
if success
|
||||
.status-block.status-block--success
|
||||
svg.status-block__icon.status-block__icon--success
|
||||
use(xlink:href='/icons/icons.svg#success')
|
||||
.status-block__content
|
||||
.status-block__title Changes saved successfully!
|
||||
.status-block__title #{translate('changesSavedLabel', currentLocale.code)}
|
||||
|
||||
if hasErrors
|
||||
.status-block.status-block--error
|
||||
svg.status-block__icon.status-block__icon--error
|
||||
use(xlink:href='/icons/icons.svg#error')
|
||||
.status-block__content
|
||||
.status-block__title Error occurred
|
||||
.status-block__message Some errors occurred. Please check the error messages next to the fields.
|
||||
.status-block__title #{translate('errorOcurredTitleLabel', currentLocale.code)}
|
||||
.status-block__message #{translate('errorOcurredMessageLabel', currentLocale.code)}
|
||||
|
||||
if space && !hasErrors
|
||||
.status-block.status-block--info
|
||||
svg.status-block__icon.status-block__icon--info
|
||||
use(xlink:href='/icons/icons.svg#info')
|
||||
.status-block__content
|
||||
.status-block__message Connected to space “#{space.name}”
|
||||
.status-block__message #{translate('connectedToSpaceLabel', currentLocale.code)} “#{space.name}”
|
||||
|
||||
form(action=`/settings` method="POST" class="form")
|
||||
.form-item
|
||||
label(for="input-space-id") Space ID
|
||||
label(for="input-space-id") #{translate('spaceIdLabel', currentLocale.code)}
|
||||
input(type="text" name="spaceId" id="input-space-id" value=settings.spaceId)
|
||||
if 'spaceId' in errors
|
||||
+renderErrors(errors.spaceId)
|
||||
.form-item__help-text The Space ID is a unique identifier for your space.
|
||||
.form-item__help-text #{translate('spaceIdHelpText', currentLocale.code)}
|
||||
|
||||
.form-item
|
||||
label(for="input-delivery-token") Content Delivery API - access token
|
||||
label(for="input-delivery-token") Content Delivery API - #{translate('accessTokenLabel', currentLocale.code)}
|
||||
input(type="text" name="deliveryToken" id="input-delivery-token" value=settings.deliveryToken)
|
||||
if 'deliveryToken' in errors
|
||||
+renderErrors(errors.deliveryToken)
|
||||
.form-item__help-text
|
||||
| View published content using this API.
|
||||
| #{translate('contentDeliveryApiHelpText', currentLocale.code)}
|
||||
a(href='https://www.contentful.com/developers/docs/references/content-delivery-api/' target='_blank' rel='noopener') Content Delivery API.
|
||||
|
||||
.form-item
|
||||
label(for="input-preview-token") Content Preview API - access token
|
||||
label(for="input-preview-token") Content Preview API - #{translate('accessTokenLabel', currentLocale.code)}
|
||||
input(type="text" name="previewToken" id="input-preview-token" value=settings.previewToken)
|
||||
if 'previewToken' in errors
|
||||
+renderErrors(errors.previewToken)
|
||||
.form-item__help-text
|
||||
| Preview unpublished content using this API (i.e. content with “Draft” status).
|
||||
| #{translate('contentPreviewApiHelpText', currentLocale.code)}
|
||||
a(href='https://www.contentful.com/developers/docs/references/content-preview-api/' target='_blank' rel='noopener') Content Preview API.
|
||||
|
||||
.form-item
|
||||
input(type="checkbox" name="editorialFeatures" id="input-editorial-features" checked=settings.editorialFeatures)
|
||||
label(for="input-editorial-features") Enable editorial features
|
||||
.form-item__help-text Enable to display an edit link and other contextual helpers for authors. You need to have access to the connected space to make this work.
|
||||
label(for="input-editorial-features") #{translate('enableEditorialFeaturesLabel', currentLocale.code)}
|
||||
.form-item__help-text #{translate('enableEditorialFeaturesHelpText', currentLocale.code)}
|
||||
|
||||
.form-item
|
||||
input.cta(type="submit" value="Save settings")
|
||||
input.cta(type="submit" value=translate('saveSettingsButtonLabel', currentLocale.code))
|
||||
|
||||
Reference in New Issue
Block a user