feat: make non default locales optional (#1109)

This commit is contained in:
Daniel Lautzenheiser 2024-04-26 12:32:10 -04:00 committed by GitHub
parent 69fc27ab6b
commit 1d0141fcc8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 49 additions and 8 deletions

View File

@ -19,6 +19,10 @@ i18n:
# Optional, defaults to the first item in locales. # Optional, defaults to the first item in locales.
# The locale to be used for fields validation and as a baseline for the entry. # The locale to be used for fields validation and as a baseline for the entry.
default_locale: en default_locale: en
# Optional, defaults to true.
# Enforce required fields in non-default locales
enforce_required_non_default: true
collections: collections:
- name: posts - name: posts
label: Posts label: Posts

View File

@ -697,7 +697,12 @@ describe('config', () => {
}, },
], ],
}).collections[0].i18n, }).collections[0].i18n,
).toEqual({ structure: 'multiple_folders', locales: ['en', 'de'], default_locale: 'en' }); ).toEqual({
structure: 'multiple_folders',
locales: ['en', 'de'],
default_locale: 'en',
enforce_required_non_default: true,
});
}); });
it('should not set root i18n on collection when collection i18n is not set', () => { it('should not set root i18n on collection when collection i18n is not set', () => {
@ -757,7 +762,12 @@ describe('config', () => {
}, },
], ],
}).collections[0].i18n, }).collections[0].i18n,
).toEqual({ structure: 'multiple_folders', locales: ['en', 'fr'], default_locale: 'fr' }); ).toEqual({
structure: 'multiple_folders',
locales: ['en', 'fr'],
default_locale: 'fr',
enforce_required_non_default: true,
});
}); });
it('should throw when i18n structure is not single_file on files collection', () => { it('should throw when i18n structure is not single_file on files collection', () => {

View File

@ -92,17 +92,24 @@ function setI18nField<T extends BaseField = UnknownField>(field: T) {
function getI18nDefaults( function getI18nDefaults(
collectionOrFileI18n: boolean | Partial<I18nInfo>, collectionOrFileI18n: boolean | Partial<I18nInfo>,
{ default_locale, locales = ['en'], structure = I18N_STRUCTURE_SINGLE_FILE }: Partial<I18nInfo>, {
default_locale,
locales = ['en'],
structure = I18N_STRUCTURE_SINGLE_FILE,
enforce_required_non_default = true,
}: Partial<I18nInfo>,
): I18nInfo { ): I18nInfo {
if (typeof collectionOrFileI18n === 'boolean') { if (typeof collectionOrFileI18n === 'boolean') {
return { default_locale, locales, structure }; return { default_locale, locales, structure, enforce_required_non_default };
} else { } else {
const mergedI18n: I18nInfo = deepmerge( const mergedI18n: I18nInfo = deepmerge(
{ default_locale, locales, structure }, { default_locale, locales, structure, enforce_required_non_default },
collectionOrFileI18n, collectionOrFileI18n,
); );
mergedI18n.locales = collectionOrFileI18n.locales ?? locales; mergedI18n.locales = collectionOrFileI18n.locales ?? locales;
mergedI18n.default_locale = collectionOrFileI18n.default_locale || locales?.[0]; mergedI18n.default_locale = collectionOrFileI18n.default_locale || locales?.[0];
mergedI18n.enforce_required_non_default =
collectionOrFileI18n.enforce_required_non_default || true;
throwOnMissingDefaultLocale(mergedI18n); throwOnMissingDefaultLocale(mergedI18n);
return mergedI18n; return mergedI18n;
} }
@ -202,6 +209,7 @@ function applyCollectionFileDefaults(
locales: collectionI18n.locales, locales: collectionI18n.locales,
default_locale: collectionI18n.default_locale, default_locale: collectionI18n.default_locale,
structure: collectionI18n.structure, structure: collectionI18n.structure,
enforce_required_non_default: collectionI18n.enforce_required_non_default,
}); });
file.i18n = fileI18n; file.i18n = fileI18n;
} else { } else {
@ -315,6 +323,7 @@ export function applyDefaults<EF extends BaseField = UnknownField>(
if (i18n) { if (i18n) {
i18n.default_locale = i18n.default_locale ?? i18n.locales[0]; i18n.default_locale = i18n.default_locale ?? i18n.locales[0];
i18n.enforce_required_non_default = i18n.enforce_required_non_default ?? true;
} }
throwOnMissingDefaultLocale(i18n); throwOnMissingDefaultLocale(i18n);

View File

@ -124,7 +124,8 @@ const EditorControl: FC<EditorControlProps> = ({
(!dirty && !submitted) || (!dirty && !submitted) ||
disabled || disabled ||
i18nDisabled || i18nDisabled ||
(forList && field.widget === 'object' && field.fields.length === 1) (forList && field.widget === 'object' && field.fields.length === 1) ||
(i18n?.enforceRequiredNonDefault === false && i18n?.currentLocale !== i18n?.defaultLocale)
) { ) {
return; return;
} }

View File

@ -88,11 +88,12 @@ const EditorControlPane: FC<EditorControlPaneProps> = ({
const i18n = useMemo(() => { const i18n = useMemo(() => {
if (hasI18n(collection)) { if (hasI18n(collection)) {
const { locales, default_locale } = getI18nInfo(collection); const { locales, default_locale, enforce_required_non_default } = getI18nInfo(collection);
return { return {
currentLocale: locale ?? locales?.[0], currentLocale: locale ?? locales?.[0],
locales, locales,
defaultLocale: default_locale, defaultLocale: default_locale,
enforceRequiredNonDefault: enforce_required_non_default,
} as I18nSettings; } as I18nSettings;
} }

View File

@ -40,6 +40,7 @@ const i18n = {
uniqueItems: true, uniqueItems: true,
}, },
default_locale: localeType, default_locale: localeType,
enforce_required_non_default: { type: 'boolean' },
}, },
}; };

View File

@ -267,6 +267,7 @@ export interface I18nSettings {
currentLocale: string; currentLocale: string;
defaultLocale: string; defaultLocale: string;
locales: string[]; locales: string[];
enforceRequiredNonDefault?: boolean;
} }
export type Format = keyof typeof formatExtensions; export type Format = keyof typeof formatExtensions;
@ -1306,6 +1307,7 @@ export interface I18nInfo {
locales: string[]; locales: string[];
default_locale?: string; default_locale?: string;
structure: I18nStructure; structure: I18nStructure;
enforce_required_non_default?: boolean;
} }
export interface ProcessedCodeLanguage { export interface ProcessedCodeLanguage {

View File

@ -343,6 +343,7 @@ export async function getI18nEntry<EF extends BaseField>(
i18nInfo = { i18nInfo = {
structure: I18N_STRUCTURE_SINGLE_FILE, structure: I18N_STRUCTURE_SINGLE_FILE,
locales: [], locales: [],
enforce_required_non_default: true,
}; };
} }

View File

@ -115,6 +115,7 @@ describe('entryDraft', () => {
locales: ['en', 'fr', 'es'], locales: ['en', 'fr', 'es'],
defaultLocale: 'en', defaultLocale: 'en',
currentLocale: 'en', currentLocale: 'en',
enforceRequiredNonDefault: true,
}, },
isMeta: false, isMeta: false,
}, },
@ -155,6 +156,7 @@ describe('entryDraft', () => {
locales: ['en', 'fr', 'es'], locales: ['en', 'fr', 'es'],
defaultLocale: 'en', defaultLocale: 'en',
currentLocale: 'en', currentLocale: 'en',
enforceRequiredNonDefault: true,
}; };
let state = entryDraftReducer(startState, { let state = entryDraftReducer(startState, {

View File

@ -25,6 +25,10 @@ i18n:
# Optional, defaults to the first item in locales. # Optional, defaults to the first item in locales.
# The locale to be used for fields validation and as a baseline for the entry. # The locale to be used for fields validation and as a baseline for the entry.
default_locale: en default_locale: en
# Optional, defaults to true.
# Enforce required fields in non-default locales
enforce_required_non_default: false
``` ```
```js ```js
@ -44,7 +48,13 @@ i18n: {
* Optional, defaults to the first item in locales. * Optional, defaults to the first item in locales.
* The locale to be used for fields validation and as a baseline for the entry. * The locale to be used for fields validation and as a baseline for the entry.
*/ */
default_locale: 'en' default_locale: 'en',
/**
* Optional, defaults to true.
* Enforce required fields in non-default locales
*/
enforce_required_non_default: false
}, },
``` ```