mirror of
https://github.com/strapi/strapi.git
synced 2025-12-13 07:55:33 +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(Array.isArray(res.body.results)).toBe(true);
|
||||||
expect(res.body.results.length).toBe(data.beds.length);
|
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 () => {
|
test('search with special characters', async () => {
|
||||||
|
|||||||
@ -745,6 +745,7 @@ describe('Core API - Validate', () => {
|
|||||||
const allDocumentFields = [
|
const allDocumentFields = [
|
||||||
// TODO: Document id should not be in attributes
|
// TODO: Document id should not be in attributes
|
||||||
'documentId',
|
'documentId',
|
||||||
|
'locale',
|
||||||
'name',
|
'name',
|
||||||
'name_non_searchable',
|
'name_non_searchable',
|
||||||
'misc',
|
'misc',
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { LoadedStrapi } from '@strapi/types';
|
|||||||
import { createTestSetup, destroyTestSetup } from '../../../utils/builder-helper';
|
import { createTestSetup, destroyTestSetup } from '../../../utils/builder-helper';
|
||||||
import { testInTransaction } from '../../../utils/index';
|
import { testInTransaction } from '../../../utils/index';
|
||||||
import resources from './resources/index';
|
import resources from './resources/index';
|
||||||
import { ARTICLE_UID, findArticlesDb } from './utils';
|
import { ARTICLE_UID, findArticlesDb, AUTHOR_UID } from './utils';
|
||||||
|
|
||||||
describe('Document Service', () => {
|
describe('Document Service', () => {
|
||||||
let testUtils;
|
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 { LoadedStrapi } from '@strapi/types';
|
||||||
import { createTestSetup, destroyTestSetup } from '../../../utils/builder-helper';
|
import { createTestSetup, destroyTestSetup } from '../../../utils/builder-helper';
|
||||||
import resources from './resources/index';
|
import resources from './resources/index';
|
||||||
import { ARTICLE_UID, findArticleDb } from './utils';
|
import { ARTICLE_UID, findArticleDb, AUTHOR_UID, findAuthorDb } from './utils';
|
||||||
|
|
||||||
describe('Document Service', () => {
|
describe('Document Service', () => {
|
||||||
let testUtils;
|
let testUtils;
|
||||||
@ -55,6 +55,17 @@ describe('Document Service', () => {
|
|||||||
expect(article).toMatchObject(articleDb);
|
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');
|
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
|
// Make sure this is sorted by order to create them
|
||||||
'api::category.category': require('./category.json'),
|
'api::category.category': require('./category.json'),
|
||||||
'api::article.article': require('./article.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': {
|
'content-types': {
|
||||||
'api::category.category': require('./category'),
|
'api::category.category': require('./category'),
|
||||||
'api::article.article': require('./article'),
|
'api::article.article': require('./article'),
|
||||||
|
'api::author.author': require('./author'),
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
'article.comp': require('./comp'),
|
'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 {
|
export interface ApiCategoryCategory extends Schema.CollectionType {
|
||||||
collectionName: 'categories';
|
collectionName: 'categories';
|
||||||
info: {
|
info: {
|
||||||
@ -674,6 +706,7 @@ declare module '@strapi/types' {
|
|||||||
'plugin::users-permissions.role': PluginUsersPermissionsRole;
|
'plugin::users-permissions.role': PluginUsersPermissionsRole;
|
||||||
'plugin::users-permissions.user': PluginUsersPermissionsUser;
|
'plugin::users-permissions.user': PluginUsersPermissionsUser;
|
||||||
'api::article.article': ApiArticleArticle;
|
'api::article.article': ApiArticleArticle;
|
||||||
|
'api::author.author': ApiAuthorAuthor;
|
||||||
'api::category.category': ApiCategoryCategory;
|
'api::category.category': ApiCategoryCategory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
import { Attribute } from '@strapi/strapi';
|
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 const ARTICLE_UID = 'api::article.article';
|
||||||
export type Article = Attribute.GetAll<typeof ARTICLE_UID> & { documentId: string; id: number };
|
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) => {
|
export const findPublishedArticlesDb = async (documentId) => {
|
||||||
return findArticlesDb({ documentId, publishedAt: { $notNull: true } });
|
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
|
* - 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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,19 @@
|
|||||||
// TODO: Move to i18n
|
// TODO: Move to i18n
|
||||||
import { Documents } from '@strapi/types';
|
import { Documents, Common } from '@strapi/types';
|
||||||
|
|
||||||
type Middleware = Documents.Middleware.Middleware<any, any>;
|
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) => {
|
export const defaultLocale: Middleware = async (ctx, next) => {
|
||||||
|
if (!isLocalizedContentType(ctx.uid)) return next(ctx);
|
||||||
if (!ctx.params) ctx.params = {};
|
if (!ctx.params) ctx.params = {};
|
||||||
|
|
||||||
// Default to en (TODO: Load default locale from db in i18n)
|
|
||||||
if (!ctx.params.locale) {
|
if (!ctx.params.locale) {
|
||||||
|
// Default to en (TODO: Load default locale from db in i18n)
|
||||||
ctx.params.locale = 'en';
|
ctx.params.locale = 'en';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,6 +24,7 @@ export const defaultLocale: Middleware = async (ctx, next) => {
|
|||||||
* Add locale lookup query to the params
|
* Add locale lookup query to the params
|
||||||
*/
|
*/
|
||||||
export const localeToLookup: Middleware = async (ctx, next) => {
|
export const localeToLookup: Middleware = async (ctx, next) => {
|
||||||
|
if (!isLocalizedContentType(ctx.uid)) return next(ctx);
|
||||||
if (!ctx.params) ctx.params = {};
|
if (!ctx.params) ctx.params = {};
|
||||||
|
|
||||||
const lookup = ctx.params.lookup || {};
|
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
|
* Translate locale status parameter into the data that will be saved
|
||||||
*/
|
*/
|
||||||
export const localeToData: Middleware = async (ctx, next) => {
|
export const localeToData: Middleware = async (ctx, next) => {
|
||||||
|
if (!isLocalizedContentType(ctx.uid)) return next(ctx);
|
||||||
if (!ctx.params) ctx.params = {};
|
if (!ctx.params) ctx.params = {};
|
||||||
|
|
||||||
const data = ctx.params.data || {};
|
const data = ctx.params.data || {};
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import enableContentType from './migrations/content-type/enable';
|
|||||||
import disableContentType from './migrations/content-type/disable';
|
import disableContentType from './migrations/content-type/disable';
|
||||||
|
|
||||||
export default ({ strapi }: { strapi: Strapi }) => {
|
export default ({ strapi }: { strapi: Strapi }) => {
|
||||||
extendLocalizedContentTypes(strapi);
|
extendContentTypes(strapi);
|
||||||
addContentManagerLocaleMiddleware(strapi);
|
addContentManagerLocaleMiddleware(strapi);
|
||||||
addContentTypeSyncHooks(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
|
* @param {Strapi} strapi
|
||||||
*/
|
*/
|
||||||
const extendLocalizedContentTypes = (strapi: Strapi) => {
|
const extendContentTypes = (strapi: Strapi) => {
|
||||||
const contentTypeService = getService('content-types');
|
|
||||||
const coreApiService = getService('core-api');
|
const coreApiService = getService('core-api');
|
||||||
|
|
||||||
Object.values(strapi.contentTypes).forEach((contentType) => {
|
Object.values(strapi.contentTypes).forEach((contentType) => {
|
||||||
if (contentTypeService.isLocalizedContentType(contentType)) {
|
const { attributes } = contentType;
|
||||||
const { attributes } = contentType;
|
|
||||||
|
|
||||||
_.set(attributes, 'localizations', {
|
_.set(attributes, 'localizations', {
|
||||||
writable: true,
|
writable: true,
|
||||||
private: false,
|
private: false,
|
||||||
configurable: false,
|
configurable: false,
|
||||||
visible: false,
|
visible: false,
|
||||||
type: 'relation',
|
type: 'relation',
|
||||||
relation: 'oneToMany',
|
relation: 'oneToMany',
|
||||||
target: contentType.uid,
|
target: contentType.uid,
|
||||||
});
|
});
|
||||||
|
|
||||||
_.set(attributes, 'locale', {
|
_.set(attributes, 'locale', {
|
||||||
writable: true,
|
writable: true,
|
||||||
private: false,
|
private: false,
|
||||||
configurable: false,
|
configurable: false,
|
||||||
visible: false,
|
visible: false,
|
||||||
type: 'string',
|
type: 'string',
|
||||||
});
|
});
|
||||||
|
|
||||||
coreApiService.addCreateLocalizationAction(contentType);
|
coreApiService.addCreateLocalizationAction(contentType);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (strapi.plugin('graphql')) {
|
if (strapi.plugin('graphql')) {
|
||||||
|
|||||||
@ -115,6 +115,8 @@ const userSchemaAdditions = () => {
|
|||||||
'publishedAt',
|
'publishedAt',
|
||||||
'strapi_stage',
|
'strapi_stage',
|
||||||
'strapi_assignee',
|
'strapi_assignee',
|
||||||
|
'locale',
|
||||||
|
'localizations',
|
||||||
];
|
];
|
||||||
|
|
||||||
return currentSchema.filter((key) => !(ignoreDiffs.includes(key) || defaultSchema.includes(key)));
|
return currentSchema.filter((key) => !(ignoreDiffs.includes(key) || defaultSchema.includes(key)));
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user