Skip to content

Commit

Permalink
feat(#158): add multilingual support
Browse files Browse the repository at this point in the history
  • Loading branch information
robedwards-cti authored and Decipher committed Mar 23, 2022
1 parent 831c698 commit 7f29a4e
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 48 deletions.
13 changes: 7 additions & 6 deletions packages/druxt/src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,8 @@ class DruxtClient {
* @example @lang js
* const collection = await this.$druxt.getCollection('node--recipe')
*/
async getCollection(type, query) {
const { href } = await this.getIndex(type)
async getCollection(type, query, prefix) {
const { href } = await this.getIndex(type, prefix)
if (!href) {
return false
}
Expand Down Expand Up @@ -324,10 +324,11 @@ class DruxtClient {
* const { href } = await this.$druxt.getIndex('node--article')
*
* @param {string} resource - (Optional) A specific resource to query.
* @param {string} prefix - (Optional) The endpoint prefix.
*
* @returns {object} The resource index object or the specified resource.
*/
async getIndex(resource) {
async getIndex(resource, prefix = '') {
if (this.index && !resource) {
return this.index
}
Expand All @@ -337,7 +338,7 @@ class DruxtClient {
}

const url = this.options.endpoint
const { data } = await this.get(url)
const { data } = await this.get(prefix + url)
let index = data.links

// Throw error if index is invalid.
Expand Down Expand Up @@ -430,12 +431,12 @@ class DruxtClient {
*
* @returns {object} The JSON:API resource data.
*/
async getResource(type, id, query) {
async getResource(type, id, query, prefix) {
if (!id || !type) {
return false
}

let { href } = await this.getIndex(type)
let { href } = await this.getIndex(type, prefix)
// @TODO - Add test coverage.
if (!href) {
href = this.options.endpoint + '/' + type.replace('--', '/')
Expand Down
14 changes: 10 additions & 4 deletions packages/druxt/src/stores/druxt.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,10 @@ const DruxtStore = ({ store }) => {
* query: new DrupalJsonApiParams().addFilter('status', '1'),
* })
*/
async getCollection ({ commit, state }, { type, query }) {
async getCollection ({ commit, state, rootState }, { type, query }) {
// Get the route prefix from the druxt-router store.
const prefix = rootState.druxtRouter.route.prefix

// Generate a hash using query data excluding the 'fields' and 'include' data.
const queryObject = getDrupalJsonApiParams(query).getQueryObject()
const hash = query ? md5(JSON.stringify({ ...queryObject, fields: {}, include: [] })) : '_default'
Expand All @@ -173,7 +176,7 @@ const DruxtStore = ({ store }) => {
}

// Get the collection using the DruxtClient instance.
const collection = await this.$druxt.getCollection(type, query)
const collection = await this.$druxt.getCollection(type, query, prefix)

// Store the collection in the DruxtStore.
commit('addCollection', { collection: { ...collection }, type, hash })
Expand All @@ -196,7 +199,10 @@ const DruxtStore = ({ store }) => {
* @example @lang js
* const resource = await this.$store.dispatch('druxt/getResource', { type: 'node--article', id })
*/
async getResource ({ commit, dispatch, state }, { type, id, query }) {
async getResource ({ commit, dispatch, state, rootState }, { type, id, query }) {
// Get the route prefix from the druxt-router store.
const prefix = rootState.druxtRouter.route.prefix

// Get the resource from the store if it's avaialble.
const storedResource = (state.resources[type] || {})[id] ?
{ ...state.resources[type][id] }
Expand Down Expand Up @@ -276,7 +282,7 @@ const DruxtStore = ({ store }) => {
// Request the resource from the DruxtClient if required.
let resource
if (!storedResource || fields) {
resource = await this.$druxt.getResource(type, id, getDrupalJsonApiParams(queryObject))
resource = await this.$druxt.getResource(type, id, getDrupalJsonApiParams(queryObject), prefix)
commit('addResource', { resource: { ...resource } })
}

Expand Down
11 changes: 6 additions & 5 deletions packages/menu/src/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ class DruxtMenu {
* @param {string} menuName - The menu name.
* @param {object} settings - The Druxt Menu query settings object.
*/
async get(menuName, settings) {
async get(menuName, settings, prefix) {
if (this.options.menu.jsonApiMenuItems) {
return this.getJsonApiMenuItems(menuName, settings)
return this.getJsonApiMenuItems(menuName, settings, prefix)
}

return this.getMenuLinkContent(menuName, settings)
return this.getMenuLinkContent(menuName, settings, prefix)
}

/**
Expand Down Expand Up @@ -138,15 +138,16 @@ class DruxtMenu {
*
* @param {string} menuName - The menu name.
* @param {object} settings - The Druxt Menu query settings object.
* @param {string} prefix - (Optional) The endpoint prefix.
*/
async getJsonApiMenuItems(menuName, settings) {
async getJsonApiMenuItems(menuName, settings, prefix = '') {
const menuItemsResource = `menu_items--${menuName}`
const resource = 'menu_link_content--menu_link_content'
const requiredFields = ['menu_name', 'parent', 'title', 'url', 'weight']

// Add the JSON API Menu items resource to the index.
await this.druxt.getIndex()
this.druxt.index[menuItemsResource] = { href: `${this.druxt.options.endpoint}/menu_items/${menuName}` }
this.druxt.index[menuItemsResource] = { href: `${prefix}${this.druxt.options.endpoint}/menu_items/${menuName}` }

// Build query.
const query = this.buildQuery(resource, menuName, requiredFields, settings)
Expand Down
7 changes: 5 additions & 2 deletions packages/menu/src/stores/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,14 @@ const DruxtMenuStore = ({ store }) => {
* @example @lang js
* await this.$store.dispatch('druxtMenu/get', { name: 'main' })
*/
async get ({ commit }, context) {
async get ({ commit, rootState }, context) {
// Get the route prefix from the druxt-router store.
const prefix = rootState.druxtRouter.route.prefix

const { name, settings } = typeof context === 'object'
? context
: { name: context }
const { entities } = (await this.$druxtMenu.get(name, settings)) || {}
const { entities } = (await this.$druxtMenu.get(name, settings, prefix)) || {}

commit('addEntities', entities)
}
Expand Down
5 changes: 4 additions & 1 deletion packages/router/src/components/DruxtRouter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ export default {
}
// Get and set the current route and redirect information.
const result = await store.dispatch('druxtRouter/get', route.fullPath)
const result = await store.dispatch('druxtRouter/get', {
path: route.params.pathMatch,
langcode: route.meta[0].langcode
})
// Process redirect.
if (result.redirect) {
Expand Down
31 changes: 25 additions & 6 deletions packages/router/src/nuxt/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,31 @@ const DruxtRouterNuxtModule = async function (moduleOptions = {}) {
})

this.extendRoutes((routes, resolve) => {
routes.push({
name: 'druxt-router',
path: '*',
component: resolve(this.options.buildDir, 'components/druxt-router.js'),
chunkName: 'druxt-router'
})
if (this.nuxt.options.i18n && this.nuxt.options.i18n.locales) {
this.nuxt.options.i18n.locales.forEach((locale) => {
routes.push({
name: `druxt-router___${locale.code}`,
path: `/${locale.code}/*`,
component: options.router.component,
chunkName: 'druxt-router',
meta: { langcode: locale.code }
})
})
routes.push({
name: 'druxt-router',
path: '/*',
component: options.router.component,
chunkName: 'druxt-router'
})
} else {
// Add Druxt router custom wildcard route.
routes.push({
name: 'druxt-router',
path: '*',
component: options.router.component,
chunkName: 'druxt-router'
})
}
})
}

Expand Down
24 changes: 14 additions & 10 deletions packages/router/src/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,28 +183,28 @@ class DruxtRouter {
*
* @returns {boolean|string} The redirect path or false.
*/
getRedirect (path, route = {}) {
getRedirect (path, route = {}, langcode = null) {
// Redirect to route provided redirect.
if (((route.redirect || [])[0] || {}).to) {
return route.redirect[0].to
}

const url = Url(path)
const url = Url('/' + path)

// Redirect to root if route is home path but path isn't root.
if (route.isHomePath) {
if (url.pathname !== '/') {
return '/'
return langcode ? `/${langcode}/` : '/'
}

return false
}

// Redirect if path does not match resolved clean url path.
if (typeof route.canonical === 'string') {
const canonicalUrl = new Url(route.canonical)

if (url.pathname !== canonicalUrl.pathname) {
if (langcode && `/${langcode + url.pathname}` !== canonicalUrl.pathname) {
return canonicalUrl.pathname
} else if (!langcode && url.pathname !== canonicalUrl.pathname) {
return canonicalUrl.pathname
}
}
Expand Down Expand Up @@ -276,7 +276,7 @@ class DruxtRouter {
* @returns {object} The JSON:API resource data.
*/
async getResourceByRoute (route) {
const resource = await this.druxt.getResource(route.jsonapi.resourceName, route.entity.uuid)
const resource = await this.druxt.getResource(route.jsonapi.resourceName, route.entity.uuid, route.prefix)
return resource.data || false
}

Expand All @@ -290,9 +290,10 @@ class DruxtRouter {
*
* @returns {object} The route object.
*/
async getRoute (path) {
async getRoute (path, langcode) {
const prefix = langcode ? langcode + '/' : ''
// @TODO - Add validation/error handling.
const url = `/router/translate-path?path=${path}`
const url = `/router/translate-path?path=${prefix + path}`

const response = await this.druxt.get(url, {
// Prevent invalid routes (404) from throwing validation errors.
Expand All @@ -318,7 +319,10 @@ class DruxtRouter {
label: data.label,
props: false,
redirect: data.redirect,
resolvedPath: Url(data.resolved).pathname
resolvedPath: Url(data.resolved).pathname,
prefix: langcode,
entity: data.entity

}

// Determine route type by configuration.
Expand Down
28 changes: 14 additions & 14 deletions packages/router/src/stores/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ const DruxtRouterStore = ({ store }) => {
* @example @lang js
* this.$store.commit('druxtRouter/addRoute', { path, route })
*/
addRoute (state, { path, route }) {
addRoute (state, { path, route, langcode }) {
if (typeof path !== 'string' || typeof route === 'undefined') {
// @TODO - Error?
return
}

state.routes[path] = route
state.routes[path + langcode] = route
},

/**
Expand All @@ -102,13 +102,13 @@ const DruxtRouterStore = ({ store }) => {
* @example @lang js
* this.$store.commit('druxtRouter/setRoute', '/')
*/
setRoute (state, path) {
if (typeof path !== 'string' || typeof state.routes[path] === 'undefined') {
setRoute (state, { path, langcode }) {
if (typeof path !== 'string' || typeof state.routes[path] + langcode === 'undefined') {
// @TODO - Error?
return
}

state.route = state.routes[path]
state.route = state.routes[path + langcode]
}
},

Expand All @@ -131,20 +131,20 @@ const DruxtRouterStore = ({ store }) => {
* @example @lang js
* const { redirect, route } = await this.$store.dispatch('druxtRouter/get', '/')
*/
async get ({ commit, dispatch }, path) {
async get ({ commit, dispatch }, { path, langcode }) {
// Get route by path from 'getRoute'.
const route = await dispatch('getRoute', path)
const route = await dispatch('getRoute', { path, langcode })

// Handle route errors.
if (route.error && typeof route.error.statusCode !== 'undefined' && ((this.app || {}).context || {}).error) {
return this.app.context.error(route.error)
}

// Set active route.
commit('setRoute', path)
commit('setRoute', { path, langcode })

// Set active redirect.
const redirect = this.$druxtRouter().getRedirect(path, route)
const redirect = this.$druxtRouter().getRedirect(path, route, langcode)
commit('setRedirect', redirect)

return { redirect, route }
Expand Down Expand Up @@ -229,19 +229,19 @@ const DruxtRouterStore = ({ store }) => {
* @example @lang js
* const route = await this.$store.dispatch('druxtRouter/getRoute', '/')
*/
async getRoute ({ commit, state }, path) {
if (typeof state.routes[path] !== 'undefined') {
return state.routes[path]
async getRoute ({ commit, state }, { path, langcode }) {
if (typeof state.routes[path + langcode] !== 'undefined') {
return state.routes[path + langcode]
}

let route
try {
route = await this.$druxtRouter().getRoute(path)
route = await this.$druxtRouter().getRoute(path, langcode)
} catch (err) {
route = { error: { statusCode: err.response.status, message: err.response.data.message } }
}

commit('addRoute', { path, route })
commit('addRoute', { path, route, langcode })

return route
}
Expand Down

0 comments on commit 7f29a4e

Please sign in to comment.