Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gatsby-plugin-manifest): add i18n, localization #13471

Merged
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
455d2dd
feat(gatsby-plugin-manifest): add i18n, localization
CanRau Apr 18, 2019
004285c
feat(gatsby-plugin-manifest): update readme
CanRau Apr 18, 2019
6d270ba
fix(gatsby-plugin-manifest): make map callback prop more readable
moonmeister Apr 24, 2019
75447d2
fix(gatsby-plugin-manifest): make find callback prop more readable
moonmeister Apr 24, 2019
4e7eaf8
fix(gatsby-plugin-manifest): make find callback prop more readable
moonmeister Apr 24, 2019
5ea90c4
docs(gatsby-plugin-manifest): decrease config header level
moonmeister Apr 24, 2019
baece08
feat(gatsby-plugin-manifest): integrate suggestions by moonmeister
CanRau Apr 24, 2019
a0daefe
feat(gatsby-plugin-manifest): incorporate suggestions
CanRau Apr 24, 2019
7af0716
docs(gatsby-plugin-manifest): merge moonmeisters description
CanRau Apr 29, 2019
3130013
feat(gatsby-plugin-manifest): merge moonmeisters naming suggestions
CanRau Apr 29, 2019
a938cba
remove accidentally commited .patch file
CanRau Apr 29, 2019
29510de
fix: issue when makeManifest is run multiple times it concatenates th…
moonmeister Jun 24, 2019
78d22f5
feat: add basic caching so an icon isn't generated multiple times dur…
moonmeister Jun 24, 2019
137e081
fix: overriting manifest icons when using unique images for different…
moonmeister Jun 24, 2019
b853cb2
refactor: modify code to only require name chache busting when a uniq…
moonmeister Jun 24, 2019
8ff5409
docs: update docs with link to i18n example
moonmeister Jun 24, 2019
1bfd8de
fix: tests and digest cache bug
moonmeister Jun 25, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions packages/gatsby-plugin-manifest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This plugin provides several features beyond manifest configuration to make your
- [Favicon support](https://www.w3.org/2005/10/howto-favicon)
- Legacy icon support (iOS)[^1]
- [Cache busting](https://www.keycdn.com/support/what-is-cache-busting)
- Localization - Provides unqiue manifests for path-based localization

Each of these features has extensive configuration available so you're always in control.

Expand Down Expand Up @@ -56,18 +57,21 @@ There are three modes in which icon generation can function: automatic, hybrid,
- Favicon - yes
- Legacy icon support - yes
- Cache busting - yes
- Localization - optional

- Hybrid - Generate a manually configured set of icons from a single source icon.

- Favicon - yes
- Legacy icon support - yes
- Cache busting - yes
- Localization - optional

- Manual - Don't generate or pre-configure any icons.

- Favicon - never
- Legacy icon support - yes
- Cache busting - never
- Localization - optional

**_IMPORTANT:_** For best results, if you're providing an icon for generation it should be...

Expand Down Expand Up @@ -132,6 +136,47 @@ In the manual mode, you are responsible for defining the entire web app manifest

### Feature configuration - **Optional**

#### Localization configuration

Localization allows you to crete unique manifests for each localized version of your site. As many languages as you want are supported. Localization requires unique paths for each language (e.g. if your default about page is at `/about`, the german(`de`) version would be `/de/about`)

The default site language should be configured in your root plugin options. Any additional languages should be defined in the `localize` array. The root settings will be used as defaults if not overridden in a locale. Any configuration option available in the root is also available in the `localize` array.

`lang` and `start_url` are the only _required_ options in the array objects. `name`, `short_name`, and `description` are [recommended](https://www.w3.org/TR/appmanifest/#dfn-directionality-capable-members) to be translated if being used in the default language. All other config options are optional. This is helpful if you want to provide unique icons for each locale.

The [`lang` option](https://www.w3.org/TR/appmanifest/#lang-member) is part of the web app manifest specification and thus is required to be a [valid language tag](https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry)

```js
// in gatsby-config.js
module.exports = {
plugins: [
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `The Cool Application`,
short_name: `Cool App`,
description: `The application does cool things and makes your life better.`,
lang: `en`,
display: `standalone`,
icon: `src/images/icon.png`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#fff`,
localize: [
{
start_url: `/de/`,
lang: `de`,
name: `Die coole Anwendung`,
short_name: `Coole Anwendung`,
description: `Die Anwendung macht coole Dinge und macht Ihr Leben besser.`,
},
],
},
},
],
}
```

#### Iterative icon options

The `icon_options` object may be used to iteratively add configuration items to the `icons` array. Any options included in this object will be merged with each object of the `icons` array (custom or default). Key value pairs already in the `icons` array will take precedence over duplicate items in the `icon_options` array.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,104 @@ Array [
]
`;

exports[`gatsby-plugin-manifest Manifest Link Generation Adds correct (default) i18n "manifest" link to head 1`] = `
Array [
<link
href="/manifest.webmanifest"
rel="manifest"
/>,
<link
href="/icons/icon-48x48.png"
rel="apple-touch-icon"
sizes="48x48"
/>,
<link
href="/icons/icon-72x72.png"
rel="apple-touch-icon"
sizes="72x72"
/>,
<link
href="/icons/icon-96x96.png"
rel="apple-touch-icon"
sizes="96x96"
/>,
<link
href="/icons/icon-144x144.png"
rel="apple-touch-icon"
sizes="144x144"
/>,
<link
href="/icons/icon-192x192.png"
rel="apple-touch-icon"
sizes="192x192"
/>,
<link
href="/icons/icon-256x256.png"
rel="apple-touch-icon"
sizes="256x256"
/>,
<link
href="/icons/icon-384x384.png"
rel="apple-touch-icon"
sizes="384x384"
/>,
<link
href="/icons/icon-512x512.png"
rel="apple-touch-icon"
sizes="512x512"
/>,
]
`;

exports[`gatsby-plugin-manifest Manifest Link Generation Adds correct (es) i18n "manifest" link to head 1`] = `
Array [
<link
href="/manifest_es.webmanifest"
rel="manifest"
/>,
<link
href="/icons/icon-48x48.png"
rel="apple-touch-icon"
sizes="48x48"
/>,
<link
href="/icons/icon-72x72.png"
rel="apple-touch-icon"
sizes="72x72"
/>,
<link
href="/icons/icon-96x96.png"
rel="apple-touch-icon"
sizes="96x96"
/>,
<link
href="/icons/icon-144x144.png"
rel="apple-touch-icon"
sizes="144x144"
/>,
<link
href="/icons/icon-192x192.png"
rel="apple-touch-icon"
sizes="192x192"
/>,
<link
href="/icons/icon-256x256.png"
rel="apple-touch-icon"
sizes="256x256"
/>,
<link
href="/icons/icon-384x384.png"
rel="apple-touch-icon"
sizes="384x384"
/>,
<link
href="/icons/icon-512x512.png"
rel="apple-touch-icon"
sizes="512x512"
/>,
]
`;

exports[`gatsby-plugin-manifest Manifest Link Generation Does not add a "theme color" meta tag if "theme_color_in_head" is set to false 1`] = `
Array [
<link
Expand Down
82 changes: 82 additions & 0 deletions packages/gatsby-plugin-manifest/src/__tests__/gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,4 +275,86 @@ describe(`Test plugin manifest options`, () => {
expect(content.icons[0].purpose).toEqual(`all`)
expect(content.icons[1].purpose).toEqual(`maskable`)
})

it(`generates all language versions`, async () => {
fs.statSync.mockReturnValueOnce({ isFile: () => true })
const pluginSpecificOptions = {
localize: [
{
...manifestOptions,
start_url: `/de/`,
lang: `de`,
},
{
...manifestOptions,
start_url: `/es/`,
lang: `es`,
},
{
...manifestOptions,
start_url: `/`,
},
],
}
const { localize, ...manifest } = pluginSpecificOptions
const expectedResults = localize.concat(manifest).map(x => {
return { ...manifest, ...x }
})

await onPostBootstrap(apiArgs, pluginSpecificOptions)

expect(fs.writeFileSync).toHaveBeenCalledWith(
expect.anything(),
JSON.stringify(expectedResults[0])
)
expect(fs.writeFileSync).toHaveBeenCalledWith(
expect.anything(),
JSON.stringify(expectedResults[1])
)
expect(fs.writeFileSync).toHaveBeenCalledWith(
expect.anything(),
JSON.stringify(expectedResults[2])
)
})

it(`merges default and language options`, async () => {
fs.statSync.mockReturnValueOnce({ isFile: () => true })
const pluginSpecificOptions = {
...manifestOptions,
localize: [
{
start_url: `/de/`,
lang: `de`,
},
{
start_url: `/es/`,
lang: `es`,
},
],
}
const { localize, ...manifest } = pluginSpecificOptions
const expectedResults = localize
.concat(manifest)
.map(({ language, manifest }) => {
return {
...manifestOptions,
...manifest,
}
})

await onPostBootstrap(apiArgs, pluginSpecificOptions)

expect(fs.writeFileSync).toHaveBeenCalledWith(
expect.anything(),
JSON.stringify(expectedResults[0])
)
expect(fs.writeFileSync).toHaveBeenCalledWith(
expect.anything(),
JSON.stringify(expectedResults[1])
)
expect(fs.writeFileSync).toHaveBeenCalledWith(
expect.anything(),
JSON.stringify(expectedResults[2])
)
})
})
33 changes: 33 additions & 0 deletions packages/gatsby-plugin-manifest/src/__tests__/gatsby-ssr.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const setHeadComponents = args => (headComponents = headComponents.concat(args))

const ssrArgs = {
setHeadComponents,
pathname: `/`,
}

describe(`gatsby-plugin-manifest`, () => {
Expand Down Expand Up @@ -91,6 +92,38 @@ describe(`gatsby-plugin-manifest`, () => {
})
expect(headComponents).toMatchSnapshot()
})

const i18nArgs = [
{
...ssrArgs,
pathname: `/about-us`,
testName: `Adds correct (default) i18n "manifest" link to head`,
},
{
...ssrArgs,
pathname: `/es/sobre-nosotros`,
testName: `Adds correct (es) i18n "manifest" link to head`,
},
]

i18nArgs.forEach(({ testName, ...args }) =>
it(testName, () => {
onRenderBody(args, {
start_url: `/`,
localize: [
{
start_url: `/de/`,
lang: `de`,
},
{
start_url: `/es/`,
lang: `es`,
},
],
})
expect(headComponents).toMatchSnapshot()
})
)
})

describe(`Legacy Icons`, () => {
Expand Down
Loading