Skip to content
This repository has been archived by the owner on Dec 27, 2022. It is now read-only.

Commit

Permalink
Merge pull request #310 from strapi/plugin-options-i18n
Browse files Browse the repository at this point in the history
Fix i18n support
  • Loading branch information
remidej authored Mar 24, 2022
2 parents 322b842 + da12da5 commit c72d6c7
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 19 deletions.
72 changes: 69 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ Source plugin for pulling documents into Gatsby from a Strapi API.
<summary><strong>Table of contents</strong></summary>

- [gatsby-source-strapi](#gatsby-source-strapi)
- [Install](#installing-the-plugin)
- [Installing the plugin](#installing-the-plugin)
- [Using yarn](#using-yarn)
- [Or using NPM](#or-using-npm)
- [Setting up the plugin](#setting-up-the-plugin)
- [Basic usage](#basic-usage)
- [Advanced usage](#advanced-usage)
- [Deep queries populate](#deep-queries-populate)
Expand All @@ -17,7 +20,14 @@ Source plugin for pulling documents into Gatsby from a Strapi API.
- [Rich text field](#rich-text-field)
- [Components](#components)
- [Dynamic zones](#dynamic-zones)
- [Internationalization](#internationalization)
- [Gatsby cloud and preview environment setup](#gatsby-cloud-and-preview-environment-setup)
- [Setup](#setup)
- [Enabling Content Sync](#enabling-content-sync)
- [Installing the @strapi/plugin-gatsby-preview](#installing-the-strapiplugin-gatsby-preview)
- [Using yarn](#using-yarn-1)
- [Using npm](#using-npm)
- [Configurations](#configurations)
- [Restrictions and limitations](#restrictions-and-limitations)

</details>
Expand All @@ -42,7 +52,7 @@ You can enable and configure this plugin in your `gatsby-config.js` file.

### Basic usage

First, you need to configure the `STRAPI_API_URL` and the `STRAPI_TOKEN` environment variables. We recommend using [`dotenv`][https://github.com/motdotla/dotenv] to expose these variables.
First, you need to configure the `STRAPI_API_URL` and the `STRAPI_TOKEN` environment variables. We recommend using [`dotenv`](https://github.com/motdotla/dotenv) to expose these variables.

Make sure to create a full-access [API token](https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/configurations/optional/api-tokens.html) in Strapi.

Expand Down Expand Up @@ -248,7 +258,7 @@ To query a specific component use the following query:

#### Dynamic zones

To query dynamic zones, , write a query using [inline GraphQL fragments](https://graphql.org/learn/queries/#inline-fragments).
To query dynamic zones, write a query using [inline GraphQL fragments](https://graphql.org/learn/queries/#inline-fragments).

You can use the following query:

Expand Down Expand Up @@ -280,6 +290,62 @@ You can use the following query:
}
```

#### Internationalization

Content types in Strapi can be localized with the [i18n plugin](https://docs.strapi.io/developer-docs/latest/plugins/i18n.html). But by default, gatsby-source-strapi will only fetch data in the default locale of your Strapi app. To specify which locale should be fetched, an `i18n` object can be provided in the content type's `pluginOptions`. You can also set the locale to `all` to get all available localizations of a content type:

```javascript
const strapiConfig = {
// ...
collectionTypes: [
{
singularName: 'article',
pluginOptions: {
i18n: {
locale: 'fr', // Only fetch a specific locale
},
},
},
],
singleTypes: [
{
singularName: 'global',
pluginOptions: {
i18n: {
locale: 'all', // Fetch all localizations
},
},
},
],
// ...
};
```

Then use the one of the following queries to fetch a localized content type:

```graphql
{
# Get content in all available localizations
allStrapiGlobal {
nodes {
locale
}
}

# Get a single type in a specific locale
strapiGlobal(locale: {eq: "fr"}) {
locale
}

# Get a collection type in a specific locale
allStrapiArticle(filter: {locale: {eq: "fr"}}) {
nodes {
locale
}
}
}
```

## Gatsby cloud and preview environment setup

### Setup
Expand Down
67 changes: 60 additions & 7 deletions src/fetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import createInstance from './axiosInstance';
import qs from 'qs';
import { cleanData } from './clean-data';

const fetchStrapiContentTypes = async (pluginOptions) => {
const axiosInstance = createInstance(pluginOptions);
const fetchStrapiContentTypes = async (strapiConfig) => {
const axiosInstance = createInstance(strapiConfig);
const [
{
data: { data: contentTypes },
Expand All @@ -24,7 +24,7 @@ const fetchStrapiContentTypes = async (pluginOptions) => {
};
};

const fetchEntity = async ({ endpoint, queryParams, uid }, ctx) => {
const fetchEntity = async ({ endpoint, queryParams, uid, pluginOptions }, ctx) => {
const { strapiConfig, reporter } = ctx;
const axiosInstance = createInstance(strapiConfig);

Expand All @@ -38,9 +38,56 @@ const fetchEntity = async ({ endpoint, queryParams, uid }, ctx) => {
try {
reporter.info(`Starting to fetch data from Strapi - ${opts.url} with ${JSON.stringify(opts)}`);

// Handle internationalization
const locale = pluginOptions?.i18n?.locale;
const otherLocales = [];

if (locale) {
// Ignore queryParams locale in favor of pluginOptions
delete queryParams.locale;

if (locale === 'all') {
// Get all available locales
const { data: response } = await axiosInstance({
...opts,
params: {
populate: {
localizations: {
fields: ['locale'],
},
},
},
});
response.data.attributes.localizations.data.forEach((localization) =>
otherLocales.push(localization.attributes.locale)
);
} else {
// Only one locale
queryParams.locale = locale;
}
}

// Fetch default entity based on request options
const { data } = await axiosInstance(opts);

return castArray(data.data).map((entry) => cleanData(entry, { ...ctx, contentTypeUid: uid }));
// Fetch other localizations of this entry if there are any
const otherLocalizationsPromises = otherLocales.map(async (locale) => {
const { data: localizationResponse } = await axiosInstance({
...opts,
params: {
...opts.params,
locale,
},
});
return localizationResponse.data;
});

// Run queries in parallel
const otherLocalizationsData = await Promise.all(otherLocalizationsPromises);

return castArray([data.data, ...otherLocalizationsData]).map((entry) =>
cleanData(entry, { ...ctx, contentTypeUid: uid })
);
} catch (error) {
// reporter.panic(
// `Failed to fetch data from Strapi ${opts.url} with ${JSON.stringify(opts)}`,
Expand All @@ -50,7 +97,7 @@ const fetchEntity = async ({ endpoint, queryParams, uid }, ctx) => {
}
};

const fetchEntities = async ({ endpoint, queryParams, uid }, ctx) => {
const fetchEntities = async ({ endpoint, queryParams, uid, pluginOptions }, ctx) => {
const { strapiConfig, reporter } = ctx;
const axiosInstance = createInstance(strapiConfig);

Expand All @@ -61,6 +108,12 @@ const fetchEntities = async ({ endpoint, queryParams, uid }, ctx) => {
paramsSerializer: (params) => qs.stringify(params, { encodeValuesOnly: true }),
};

// Use locale from pluginOptions if it's defined
if (pluginOptions?.i18n?.locale) {
delete queryParams.locale;
queryParams.locale = pluginOptions.i18n.locale;
}

try {
reporter.info(
`Starting to fetch data from Strapi - ${opts.url} with ${JSON.stringify(opts.params)}`
Expand All @@ -78,7 +131,7 @@ const fetchEntities = async ({ endpoint, queryParams, uid }, ctx) => {
length: pageCount - page,
}).map((_, i) => i + page + 1);

const arrayOfPromises = pagesToGet.map((page) => {
const fetchPagesPromises = pagesToGet.map((page) => {
return (async () => {
const options = {
...opts,
Expand All @@ -104,7 +157,7 @@ const fetchEntities = async ({ endpoint, queryParams, uid }, ctx) => {
})();
});

const results = await Promise.all(arrayOfPromises);
const results = await Promise.all(fetchPagesPromises);

const cleanedData = [...data, ...flattenDeep(results)].map((entry) =>
cleanData(entry, { ...ctx, contentTypeUid: uid })
Expand Down
16 changes: 8 additions & 8 deletions src/gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,22 @@ exports.sourceNodes = async (
getNodes,
getNode,
},
pluginOptions
strapiConfig
) => {
// Cast singleTypes and collectionTypes to empty arrays if they're not defined
if (!Array.isArray(pluginOptions.singleTypes)) {
pluginOptions.singleTypes = [];
if (!Array.isArray(strapiConfig.singleTypes)) {
strapiConfig.singleTypes = [];
}
if (!Array.isArray(pluginOptions.collectionTypes)) {
pluginOptions.collectionTypes = [];
if (!Array.isArray(strapiConfig.collectionTypes)) {
strapiConfig.collectionTypes = [];
}

const { schemas } = await fetchStrapiContentTypes(pluginOptions);
const { schemas } = await fetchStrapiContentTypes(strapiConfig);

const { deleteNode, touchNode } = actions;

const ctx = {
strapiConfig: pluginOptions,
strapiConfig,
actions,
schemas,
createContentDigest,
Expand All @@ -58,7 +58,7 @@ exports.sourceNodes = async (

existingNodes.forEach((n) => touchNode(n));

const endpoints = getEndpoints(pluginOptions, schemas);
const endpoints = getEndpoints(strapiConfig, schemas);

const lastFetched = await cache.get(LAST_FETCHED_KEY);

Expand Down
4 changes: 3 additions & 1 deletion src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ const getEndpoints = ({ collectionTypes, singleTypes }, schemas) => {
)
.map(({ schema: { kind, singularName, pluralName }, uid }) => {
const options = types.find((config) => config.singularName === singularName);
const { queryParams, queryLimit } = options;
const { queryParams, queryLimit, pluginOptions } = options;

if (kind === 'singleType') {
return {
Expand All @@ -110,6 +110,7 @@ const getEndpoints = ({ collectionTypes, singleTypes }, schemas) => {
queryParams: queryParams || {
populate: '*',
},
pluginOptions,
};
}

Expand All @@ -127,6 +128,7 @@ const getEndpoints = ({ collectionTypes, singleTypes }, schemas) => {
},
populate: queryParams?.populate || '*',
},
pluginOptions,
};
});

Expand Down

0 comments on commit c72d6c7

Please sign in to comment.