mirror of
https://github.com/strapi/strapi.git
synced 2025-12-12 15:32:42 +00:00
Merge pull request #19058 from strapi/v5/extend-locale-attr-to-all-ct
feat: extend i18n attributes to every content type
This commit is contained in:
commit
d39441e3c2
@ -181,7 +181,10 @@ describe('Search query', () => {
|
||||
|
||||
expect(Array.isArray(res.body.results)).toBe(true);
|
||||
expect(res.body.results.length).toBe(data.beds.length);
|
||||
expect(res.body.results.map(omit(CREATOR_FIELDS))).toEqual(expect.arrayContaining(data.beds));
|
||||
// TODO V5: Filter out i18n fields if content type is not localized
|
||||
expect(res.body.results.map(omit([...CREATOR_FIELDS, 'localizations']))).toEqual(
|
||||
expect.arrayContaining(data.beds)
|
||||
);
|
||||
});
|
||||
|
||||
test('search with special characters', async () => {
|
||||
|
||||
@ -745,6 +745,7 @@ describe('Core API - Validate', () => {
|
||||
const allDocumentFields = [
|
||||
// TODO: Document id should not be in attributes
|
||||
'documentId',
|
||||
'locale',
|
||||
'name',
|
||||
'name_non_searchable',
|
||||
'misc',
|
||||
|
||||
@ -2,7 +2,7 @@ import { LoadedStrapi } from '@strapi/types';
|
||||
import { createTestSetup, destroyTestSetup } from '../../../utils/builder-helper';
|
||||
import { testInTransaction } from '../../../utils/index';
|
||||
import resources from './resources/index';
|
||||
import { ARTICLE_UID, findArticlesDb } from './utils';
|
||||
import { ARTICLE_UID, findArticlesDb, AUTHOR_UID } from './utils';
|
||||
|
||||
describe('Document Service', () => {
|
||||
let testUtils;
|
||||
@ -118,5 +118,22 @@ describe('Document Service', () => {
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
it(
|
||||
'ignores locale parameter on non-localized content type',
|
||||
testInTransaction(async () => {
|
||||
const author = await strapi.documents(AUTHOR_UID).create({
|
||||
// Should be ignored on non-localized content types
|
||||
locale: 'fr',
|
||||
data: { name: 'Author' },
|
||||
});
|
||||
|
||||
// verify that the returned document was updated
|
||||
expect(author).toMatchObject({
|
||||
name: 'Author',
|
||||
locale: null, // should be null, as it is not a localized content type
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { LoadedStrapi } from '@strapi/types';
|
||||
import { createTestSetup, destroyTestSetup } from '../../../utils/builder-helper';
|
||||
import resources from './resources/index';
|
||||
import { ARTICLE_UID, findArticleDb } from './utils';
|
||||
import { ARTICLE_UID, findArticleDb, AUTHOR_UID, findAuthorDb } from './utils';
|
||||
|
||||
describe('Document Service', () => {
|
||||
let testUtils;
|
||||
@ -55,6 +55,17 @@ describe('Document Service', () => {
|
||||
expect(article).toMatchObject(articleDb);
|
||||
});
|
||||
|
||||
it('ignores locale parameter on non-localized content type', async () => {
|
||||
const authorDb = await findAuthorDb({ name: 'Author1-Draft' });
|
||||
|
||||
// Locale should be ignored on non-localized content types
|
||||
const author = await strapi.documents(AUTHOR_UID).findOne(authorDb.documentId, {
|
||||
locale: 'en',
|
||||
});
|
||||
|
||||
expect(author).toMatchObject(authorDb);
|
||||
});
|
||||
|
||||
it.todo('ignores pagination parameters');
|
||||
});
|
||||
});
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"documentId": "Author1",
|
||||
"name": "Author1-Draft",
|
||||
"publishedAt": null,
|
||||
"locale": null
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"documentId": "Author2",
|
||||
"name": "Author2-Draft",
|
||||
"publishedAt": null,
|
||||
"locale": null
|
||||
}
|
||||
]
|
||||
@ -5,5 +5,6 @@ module.exports = {
|
||||
// Make sure this is sorted by order to create them
|
||||
'api::category.category': require('./category.json'),
|
||||
'api::article.article': require('./article.json'),
|
||||
'api::author.author': require('./author.json'),
|
||||
},
|
||||
};
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
kind: 'collectionType',
|
||||
collectionName: 'authors',
|
||||
singularName: 'author',
|
||||
pluralName: 'authors',
|
||||
displayName: 'Author',
|
||||
description: '',
|
||||
draftAndPublish: true,
|
||||
pluginOptions: {
|
||||
i18n: {
|
||||
localized: false,
|
||||
},
|
||||
},
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
pluginOptions: {
|
||||
i18n: {
|
||||
localized: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -4,6 +4,7 @@ module.exports = {
|
||||
'content-types': {
|
||||
'api::category.category': require('./category'),
|
||||
'api::article.article': require('./article'),
|
||||
'api::author.author': require('./author'),
|
||||
},
|
||||
components: {
|
||||
'article.comp': require('./comp'),
|
||||
|
||||
@ -618,6 +618,38 @@ export interface ApiArticleArticle extends Schema.CollectionType {
|
||||
};
|
||||
}
|
||||
|
||||
export interface ApiAuthorAuthor extends Schema.CollectionType {
|
||||
collectionName: 'authors';
|
||||
info: {
|
||||
singularName: 'author';
|
||||
pluralName: 'authors';
|
||||
displayName: 'Author';
|
||||
description: '';
|
||||
};
|
||||
pluginOptions: {
|
||||
i18n: {
|
||||
localized: false;
|
||||
};
|
||||
};
|
||||
attributes: {
|
||||
name: Attribute.String &
|
||||
Attribute.SetPluginOptions<{
|
||||
i18n: {
|
||||
localized: false;
|
||||
};
|
||||
}>;
|
||||
createdAt: Attribute.DateTime;
|
||||
updatedAt: Attribute.DateTime;
|
||||
publishedAt: Attribute.DateTime;
|
||||
createdBy: Attribute.Relation<'api::author.author', 'oneToOne', 'admin::user'> &
|
||||
Attribute.Private;
|
||||
updatedBy: Attribute.Relation<'api::author.author', 'oneToOne', 'admin::user'> &
|
||||
Attribute.Private;
|
||||
localizations: Attribute.Relation<'api::author.author', 'oneToMany', 'api::author.author'>;
|
||||
locale: Attribute.String;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ApiCategoryCategory extends Schema.CollectionType {
|
||||
collectionName: 'categories';
|
||||
info: {
|
||||
@ -674,6 +706,7 @@ declare module '@strapi/types' {
|
||||
'plugin::users-permissions.role': PluginUsersPermissionsRole;
|
||||
'plugin::users-permissions.user': PluginUsersPermissionsUser;
|
||||
'api::article.article': ApiArticleArticle;
|
||||
'api::author.author': ApiAuthorAuthor;
|
||||
'api::category.category': ApiCategoryCategory;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import { Attribute } from '@strapi/strapi';
|
||||
|
||||
export const AUTHOR_UID = 'api::author.author';
|
||||
export type Author = Attribute.GetAll<typeof AUTHOR_UID> & { documentId: string; id: number };
|
||||
|
||||
export const ARTICLE_UID = 'api::article.article';
|
||||
export type Article = Attribute.GetAll<typeof ARTICLE_UID> & { documentId: string; id: number };
|
||||
|
||||
@ -14,3 +17,15 @@ export const findArticlesDb = async (where: any) => {
|
||||
export const findPublishedArticlesDb = async (documentId) => {
|
||||
return findArticlesDb({ documentId, publishedAt: { $notNull: true } });
|
||||
};
|
||||
|
||||
export const findAuthorDb = async (where: any) => {
|
||||
return (await strapi.query(AUTHOR_UID).findOne({ where })) as Author | undefined;
|
||||
};
|
||||
|
||||
export const findAuthorsDb = async (where: any) => {
|
||||
return (await strapi.query(AUTHOR_UID).findMany({ where })) as Author[];
|
||||
};
|
||||
|
||||
export const findPublishedAuthorsDb = async (documentId) => {
|
||||
return findAuthorsDb({ documentId, publishedAt: { $notNull: true } });
|
||||
};
|
||||
|
||||
@ -276,10 +276,8 @@ export const CMReleasesContainer = () => {
|
||||
|
||||
/**
|
||||
* - Impossible to add entry to release before it exists
|
||||
* - Content types without draft and publish cannot add entries to release
|
||||
* TODO v5: All contentTypes will have draft and publish enabled
|
||||
*/
|
||||
if (isCreatingEntry || !contentType?.options?.draftAndPublish) {
|
||||
if (isCreatingEntry) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -1,13 +1,19 @@
|
||||
// TODO: Move to i18n
|
||||
import { Documents } from '@strapi/types';
|
||||
import { Documents, Common } from '@strapi/types';
|
||||
|
||||
type Middleware = Documents.Middleware.Middleware<any, any>;
|
||||
|
||||
const isLocalizedContentType = (uid: Common.UID.Schema) => {
|
||||
const model = strapi.getModel(uid);
|
||||
return strapi.plugin('i18n').service('content-types').isLocalizedContentType(model);
|
||||
};
|
||||
|
||||
export const defaultLocale: Middleware = async (ctx, next) => {
|
||||
if (!isLocalizedContentType(ctx.uid)) return next(ctx);
|
||||
if (!ctx.params) ctx.params = {};
|
||||
|
||||
// Default to en (TODO: Load default locale from db in i18n)
|
||||
if (!ctx.params.locale) {
|
||||
// Default to en (TODO: Load default locale from db in i18n)
|
||||
ctx.params.locale = 'en';
|
||||
}
|
||||
|
||||
@ -18,6 +24,7 @@ export const defaultLocale: Middleware = async (ctx, next) => {
|
||||
* Add locale lookup query to the params
|
||||
*/
|
||||
export const localeToLookup: Middleware = async (ctx, next) => {
|
||||
if (!isLocalizedContentType(ctx.uid)) return next(ctx);
|
||||
if (!ctx.params) ctx.params = {};
|
||||
|
||||
const lookup = ctx.params.lookup || {};
|
||||
@ -34,6 +41,7 @@ export const localeToLookup: Middleware = async (ctx, next) => {
|
||||
* Translate locale status parameter into the data that will be saved
|
||||
*/
|
||||
export const localeToData: Middleware = async (ctx, next) => {
|
||||
if (!isLocalizedContentType(ctx.uid)) return next(ctx);
|
||||
if (!ctx.params) ctx.params = {};
|
||||
|
||||
const data = ctx.params.data || {};
|
||||
|
||||
@ -9,7 +9,7 @@ import enableContentType from './migrations/content-type/enable';
|
||||
import disableContentType from './migrations/content-type/disable';
|
||||
|
||||
export default ({ strapi }: { strapi: Strapi }) => {
|
||||
extendLocalizedContentTypes(strapi);
|
||||
extendContentTypes(strapi);
|
||||
addContentManagerLocaleMiddleware(strapi);
|
||||
addContentTypeSyncHooks(strapi);
|
||||
};
|
||||
@ -46,37 +46,35 @@ const addContentTypeSyncHooks = (strapi: Strapi) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds locale and localization fields to localized content types
|
||||
* Adds locale and localization fields to all content types
|
||||
* Even if content type is not localized, it will have these fields
|
||||
* @param {Strapi} strapi
|
||||
*/
|
||||
const extendLocalizedContentTypes = (strapi: Strapi) => {
|
||||
const contentTypeService = getService('content-types');
|
||||
const extendContentTypes = (strapi: Strapi) => {
|
||||
const coreApiService = getService('core-api');
|
||||
|
||||
Object.values(strapi.contentTypes).forEach((contentType) => {
|
||||
if (contentTypeService.isLocalizedContentType(contentType)) {
|
||||
const { attributes } = contentType;
|
||||
const { attributes } = contentType;
|
||||
|
||||
_.set(attributes, 'localizations', {
|
||||
writable: true,
|
||||
private: false,
|
||||
configurable: false,
|
||||
visible: false,
|
||||
type: 'relation',
|
||||
relation: 'oneToMany',
|
||||
target: contentType.uid,
|
||||
});
|
||||
_.set(attributes, 'localizations', {
|
||||
writable: true,
|
||||
private: false,
|
||||
configurable: false,
|
||||
visible: false,
|
||||
type: 'relation',
|
||||
relation: 'oneToMany',
|
||||
target: contentType.uid,
|
||||
});
|
||||
|
||||
_.set(attributes, 'locale', {
|
||||
writable: true,
|
||||
private: false,
|
||||
configurable: false,
|
||||
visible: false,
|
||||
type: 'string',
|
||||
});
|
||||
_.set(attributes, 'locale', {
|
||||
writable: true,
|
||||
private: false,
|
||||
configurable: false,
|
||||
visible: false,
|
||||
type: 'string',
|
||||
});
|
||||
|
||||
coreApiService.addCreateLocalizationAction(contentType);
|
||||
}
|
||||
coreApiService.addCreateLocalizationAction(contentType);
|
||||
});
|
||||
|
||||
if (strapi.plugin('graphql')) {
|
||||
|
||||
@ -115,6 +115,8 @@ const userSchemaAdditions = () => {
|
||||
'publishedAt',
|
||||
'strapi_stage',
|
||||
'strapi_assignee',
|
||||
'locale',
|
||||
'localizations',
|
||||
];
|
||||
|
||||
return currentSchema.filter((key) => !(ignoreDiffs.includes(key) || defaultSchema.includes(key)));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user