Skip to content

Commit

Permalink
feat(gatsby-theme-i18n): Add "prefixDefault" option (#75)
Browse files Browse the repository at this point in the history
  • Loading branch information
LekoArts authored Jan 6, 2021
1 parent 6dd2936 commit 631ae27
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 18 deletions.
11 changes: 6 additions & 5 deletions packages/gatsby-theme-i18n/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,12 @@ You can also see an [official example](https://github.com/gatsbyjs/themes/tree/m

### Theme options

| Key | Default Value | Description |
| ------------- | ------------- | ------------------------------------------------------------------------------------------------------------------- |
| `defaultLang` | `en` | The locale that is your default language. For this language no prefixed routes will be created. |
| `configPath` | none | Path to the config file |
| `locales` | `null` | A string of locales (divided by spaces) to only build a subset of the locales defined in `configPath`, e.g. `en de` |
| Key | Default Value | Description |
| --------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `defaultLang` | `en` | The locale that is your default language. For this language no prefixed routes will be created unless you set the option `prefixDefault`. |
| `prefixDefault` | `false` | All routes will be prefixed, including the `defaultLang` |
| `configPath` | none | Path to the config file |
| `locales` | `null` | A string of locales (divided by spaces) to only build a subset of the locales defined in `configPath`, e.g. `en de` |

You can pass additional options in as they'll be forwarded to the plugin. You can query all options in GraphQL on the `themeI18N` type.

Expand Down
55 changes: 50 additions & 5 deletions packages/gatsby-theme-i18n/gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ const fs = require(`fs`)
const path = require(`path`)
const mkdirp = require(`mkdirp`)
const { withDefaults } = require(`./utils/default-options`)
const { localizedPath, getLanguages } = require(`./src/helpers`)
const {
localizedPath,
getLanguages,
getDefaultLanguage,
} = require(`./src/helpers`)

function writeFile(filePath, data, reporter) {
// Check if config file already exists
Expand Down Expand Up @@ -69,6 +73,7 @@ exports.createSchemaCustomization = ({ actions }) => {
createTypes(`
type ThemeI18n implements Node {
defaultLang: String
prefixDefault: Boolean
configPath: String
config: [Locale]
}
Expand Down Expand Up @@ -131,26 +136,43 @@ exports.onCreateNode = ({ node, actions }, themeOptions) => {

exports.onCreatePage = ({ page, actions }, themeOptions) => {
const { createPage, deletePage } = actions
const { configPath, defaultLang, locales } = withDefaults(themeOptions)
const { configPath, defaultLang, locales, prefixDefault } = withDefaults(
themeOptions
)
// Check if originalPath was already set and bail early as otherwise an infinite loop could occur
// as other plugins like gatsby-plugin-mdx could modify this
if (page.context.originalPath) {
return
}

const originalPath = page.path

deletePage(page)

const configLocales = require(configPath)

const languages = getLanguages(defaultLang, configLocales, locales)
const languages = getLanguages({ locales: configLocales, localeStr: locales })
const defaultLocale = getDefaultLanguage({
locales: configLocales,
defaultLang,
})

languages.forEach((locale) => {
const newPage = {
...page,
path: localizedPath(defaultLang, locale.code, page.path),
path: localizedPath({
defaultLang,
prefixDefault,
locale: locale.code,
path: originalPath,
}),
matchPath: page.matchPath
? localizedPath(defaultLang, locale.code, page.matchPath)
? localizedPath({
defaultLang,
prefixDefault,
locale: locale.code,
path: page.matchPath,
})
: page.matchPath,
context: {
...page.context,
Expand All @@ -169,4 +191,27 @@ exports.onCreatePage = ({ page, actions }, themeOptions) => {

createPage(newPage)
})

// When prefixDefault is set the default development & production 404 pages
// will be deleted but not re-created in the above `languages.forEach` segment
// Thus we'll re-create them manually here

const notFoundPages = [`/404/`, `/404.html`, `/dev-404-page/`]

if (prefixDefault) {
if (notFoundPages.includes(originalPath)) {
const newPage = {
...page,
context: {
...page.context,
locale: defaultLocale.code,
hrefLang: defaultLocale.hrefLang,
originalPath,
dateFormat: defaultLocale.dateFormat,
},
}

createPage(newPage)
}
}
}
14 changes: 12 additions & 2 deletions packages/gatsby-theme-i18n/src/components/localized-link.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,18 @@ import { localizedPath } from "../helpers"
import { useLocalization } from "../hooks/use-localization"

export const LocalizedLink = ({ to, language, ...props }) => {
const { defaultLang, locale } = useLocalization()
const { defaultLang, prefixDefault, locale } = useLocalization()
const linkLocale = language || locale

return <Link {...props} to={localizedPath(defaultLang, linkLocale, to)} />
return (
<Link
{...props}
to={localizedPath({
defaultLang,
prefixDefault,
locale: linkLocale,
path: to,
})}
/>
)
}
14 changes: 12 additions & 2 deletions packages/gatsby-theme-i18n/src/components/localized-router.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,18 @@ import { Router } from "@reach/router"
import { useLocalization } from "../hooks/use-localization"

export const LocalizedRouter = ({ basePath, children, ...props }) => {
const { localizedPath, locale, defaultLang } = useLocalization()
const path = localizedPath(defaultLang, locale, basePath)
const {
localizedPath,
locale,
defaultLang,
prefixDefault,
} = useLocalization()
const path = localizedPath({
defaultLang,
prefixDefault,
locale,
path: basePath,
})

return (
<Router basepath={path} {...props}>
Expand Down
11 changes: 8 additions & 3 deletions packages/gatsby-theme-i18n/src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ function isDefaultLang(locale, defaultLang) {
return locale === defaultLang
}

function localizedPath(defaultLang, locale, path) {
function localizedPath({ defaultLang, prefixDefault, locale, path }) {
// The default language isn't prefixed
if (isDefaultLang(locale, defaultLang)) {
if (isDefaultLang(locale, defaultLang) && !prefixDefault) {
return path
}

Expand All @@ -21,7 +21,7 @@ function localizedPath(defaultLang, locale, path) {
return `/${locale}${path}`
}

function getLanguages(defaultLang, locales, localeStr) {
function getLanguages({ locales, localeStr }) {
// If "localeStr" is not defined, return the list of locales from the i18n config file
if (!localeStr) {
return locales
Expand All @@ -45,7 +45,12 @@ function getLanguages(defaultLang, locales, localeStr) {
return langs
}

function getDefaultLanguage({ locales, defaultLang }) {
return locales.find((locale) => locale.code === defaultLang)
}

module.exports = {
localizedPath,
getLanguages,
getDefaultLanguage,
}
4 changes: 3 additions & 1 deletion packages/gatsby-theme-i18n/src/hooks/use-localization.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import { localizedPath } from "../helpers"
const useLocalization = () => {
const locale = React.useContext(LocaleContext)
const {
themeI18N: { defaultLang, config },
themeI18N: { defaultLang, prefixDefault, config },
} = useStaticQuery(graphql`
query LocalizationConfigQuery {
themeI18N {
defaultLang
prefixDefault
config {
code
hrefLang
Expand All @@ -26,6 +27,7 @@ const useLocalization = () => {
return {
locale,
defaultLang,
prefixDefault,
config,
localizedPath,
}
Expand Down
3 changes: 3 additions & 0 deletions packages/gatsby-theme-i18n/utils/default-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ function withDefaults(themeOptions) {
...themeOptions,
configPath: themeOptions.configPath,
defaultLang: themeOptions.defaultLang || defaultLang,
prefixDefault: themeOptions.prefixDefault
? themeOptions.prefixDefault
: false,
locales: themeOptions.locales || null,
}
}
Expand Down
2 changes: 2 additions & 0 deletions starters/example-i18n/src/components/name.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import * as React from "react"
import Layout from "./layout"
import { LocalizedLink } from "gatsby-theme-i18n"
import SEO from "./seo"

const Name = ({ name, locale }) => (
<Layout>
<SEO title={name} />
<h1>
{name} & {locale}
</h1>
Expand Down
19 changes: 19 additions & 0 deletions starters/example-i18n/src/pages/404.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as React from "react"
import { LocalizedLink } from "gatsby-theme-i18n"
import Layout from "../components/layout"
import SEO from "../components/seo"

const NotFound = () => {
return (
<Layout>
<SEO title="404 - Page Not Found" />
<h1>404</h1>
<p>Page Not Found</p>
<p>
<LocalizedLink to="/">Link to index page</LocalizedLink>
</p>
</Layout>
)
}

export default NotFound

0 comments on commit 631ae27

Please sign in to comment.