Skip to content

Commit

Permalink
feature: Added the ability to localize RJSF internal strings
Browse files Browse the repository at this point in the history
True fix for #205 to support localizing the internal strings in @rjsf
- In `@rjsf/utils`, added `TranslatableString` enum and `englishStringTranslator()` and `replaceStringParameters()` to support localization
  - Also updated the `Registry` type to add the `translateString` function
  - Added 100% unit testing for the new functions
- In `@rjsf/core`, added a new `translateString` prop to `FormProps` as well as using that prop in the `registry` if provided
  - Updated the `getDefaultRegistry()` to set `translateString` to `englishStringTranslator`
  - Updated `ArrayField`, `BooleanField`, `MultiSchemaField`, `ObjectField`, `SchemaField`, `AddButton`, `IconButton`s, `ErrorList`, `WrapIfAdditionalTemplate` and `AltDateWidget` and `FileWidget` to use `translateString`
  - Added the `markdown-to-jsx` to support localizing the `UnsupportedField`
- In all the themes, updated `ErrorList`, `IconButton`s, `AddButton`, `WrapIfAdditionalTemplate` and where applicable `AltDateWidget` to use `translateString` from the registry
  - Updated the snapshots for `UnsupportedField` based on the cleaned up translation formatting
- In `@rjsf/chakra-ui`, updated `TextAreaWidget` and `UpDownWidget` to switch `??` syntax to `||`
- In `@rjsf/semantic-ui`, updated the `FieldErrorTemplate` and `FieldHelpTemplate` to use the `errorId()` and `helpId()` functions
- Updated the `utility-functions` docs for the enums and the new functions
- Updated the `form-props` docs to describe the new `translateString` prop
- Updated the `CHANGELOG` accordingly
  • Loading branch information
heath-freenome committed Feb 27, 2023
1 parent 8be4ef2 commit d7919a8
Show file tree
Hide file tree
Showing 72 changed files with 897 additions and 227 deletions.
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,37 @@ it according to semantic versioning. For example, if your PR adds a breaking cha
should change the heading of the (upcoming) version to include a major version bump.
-->
# 5.2.0

## @rjsf/antd
- Updated `ErrorList`, `IconButton`s, `WrapIfAdditionalTemplate` and `AltDateWidget` to use the new `translateString()` function to support localization

## @rjsf/bootstrap-4
- Updated `AddButton`, `ErrorList`, `IconButton`s and `WrapIfAdditionalTemplate` to use the new `translateString()` function to support localization

## @rjsf/chakra-ui
- Updated `AddButton`, `ErrorList`, `IconButton`s, `WrapIfAdditionalTemplate` and `AltDateWidget` to use the new `translateString()` function to support localization

## @rjsf/core
- Updated `ArrayField`, `BooleanField`, `MultiSchemaField`, `ObjectField`, `SchemaField`, `AddButton`, `IconButton`s, `ErrorList`, `WrapIfAdditionalTemplate` and `AltDateWidget` and `FileWidget` to use the new `translateString()` function to support localization
- Also updated `Form` to take a new optional `translateString` prop and `getDefaultRegistry()` to set `translateString` to `englishStringTranslator()`

## @rjsf/fluent-ui
- Updated `AddButton`, `ColorWidget`, `ErrorList`, `IconButton`s and `UpDownWidget` to use the new `translateString()` function to support localization

## @rjsf/material-ui
- Updated `AddButton`, `ErrorList`, `IconButton`s and `WrapIfAdditionalTemplate` to use the new `translateString()` function to support localization

## @rjsf/mui
- Updated `AddButton`, `ErrorList`, `IconButton`s and `WrapIfAdditionalTemplate` to use the new `translateString()` function to support localization

## @rjsf/semantic-ui
- Updated `AddButton`, `ErrorList`, `IconButton`s and `WrapIfAdditionalTemplate` to use the new `translateString()` function to support localization

## Dev / docs / playground
- Updated the `utility-functions` documentation for the `enums` and `englishStringTranslator()` & `replaceStringParameters()` functions
- Updated the `form-props` documentation for the new, optional `translateString` prop on `Form`

# 5.1.0

## @rjsf/bootstrap-4
Expand Down
6 changes: 4 additions & 2 deletions packages/antd/src/templates/ErrorList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
FormContextType,
RJSFSchema,
StrictRJSFSchema,
TranslatableString,
} from "@rjsf/utils";

/** The `ErrorList` component is the template that renders the all the errors associated with the fields in the `Form`
Expand All @@ -18,7 +19,8 @@ export default function ErrorList<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>({ errors }: ErrorListProps<T, S, F>) {
>({ errors, registry }: ErrorListProps<T, S, F>) {
const { translateString } = registry;
const renderErrors = () => (
<List className="list-group" size="small">
{errors.map((error, index) => (
Expand All @@ -36,7 +38,7 @@ export default function ErrorList<
<Alert
className="panel panel-danger errors"
description={renderErrors()}
message="Errors"
message={translateString(TranslatableString.ErrorsLabel)}
type="error"
/>
);
Expand Down
31 changes: 27 additions & 4 deletions packages/antd/src/templates/IconButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
IconButtonProps,
RJSFSchema,
StrictRJSFSchema,
TranslatableString,
} from "@rjsf/utils";

// The `type` for IconButtonProps collides with the `type` for `ButtonProps` so omit it to avoid Typescript issue
Expand Down Expand Up @@ -39,9 +40,12 @@ export function AddButton<
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: AntdIconButtonProps<T, S, F>) {
const {
registry: { translateString },
} = props;
return (
<IconButton
title="Add Item"
title={translateString(TranslatableString.AddItemButton)}
{...props}
block
iconType="primary"
Expand All @@ -55,8 +59,15 @@ export function MoveDownButton<
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: AntdIconButtonProps<T, S, F>) {
const {
registry: { translateString },
} = props;
return (
<IconButton title="Move down" {...props} icon={<ArrowDownOutlined />} />
<IconButton
title={translateString(TranslatableString.MoveDownButton)}
{...props}
icon={<ArrowDownOutlined />}
/>
);
}

Expand All @@ -65,7 +76,16 @@ export function MoveUpButton<
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: AntdIconButtonProps<T, S, F>) {
return <IconButton title="Move up" {...props} icon={<ArrowUpOutlined />} />;
const {
registry: { translateString },
} = props;
return (
<IconButton
title={translateString(TranslatableString.MoveUpButton)}
{...props}
icon={<ArrowUpOutlined />}
/>
);
}

export function RemoveButton<
Expand All @@ -75,9 +95,12 @@ export function RemoveButton<
>(props: AntdIconButtonProps<T, S, F>) {
// The `block` prop is not part of the `IconButtonProps` defined in the template, so get it from the uiSchema instead
const options = getUiOptions<T, S, F>(props.uiSchema);
const {
registry: { translateString },
} = props;
return (
<IconButton
title="Remove"
title={translateString(TranslatableString.RemoveButton)}
{...props}
danger
block={!!options.block}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
FormContextType,
RJSFSchema,
StrictRJSFSchema,
TranslatableString,
WrapIfAdditionalTemplateProps,
} from "@rjsf/utils";

Expand Down Expand Up @@ -53,10 +54,10 @@ export default function WrapIfAdditionalTemplate<
wrapperCol = VERTICAL_WRAPPER_COL,
wrapperStyle,
} = registry.formContext;
const { templates, translateString } = registry;
// Button templates are not overridden in the uiSchema
const { RemoveButton } = registry.templates.ButtonTemplates;

const keyLabel = `${label} Key`; // i18n ?
const { RemoveButton } = templates.ButtonTemplates;
const keyLabel = translateString(TranslatableString.KeyLabel, [label]);
const additional = ADDITIONAL_PROPERTY_FLAG in schema;

if (!additional) {
Expand Down
10 changes: 6 additions & 4 deletions packages/antd/src/widgets/AltDateWidget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import {
toDateString,
DateObject,
FormContextType,
GenericObjectType,
RJSFSchema,
StrictRJSFSchema,
TranslatableString,
WidgetProps,
GenericObjectType,
} from "@rjsf/utils";

type DateElementProps<
Expand Down Expand Up @@ -92,7 +93,8 @@ export default function AltDateWidget<
showTime,
value,
} = props;
const { SelectWidget } = registry.widgets;
const { translateString, widgets } = registry;
const { SelectWidget } = widgets;
const { rowGutter = 24 } = formContext as GenericObjectType;

const [state, setState] = useState(parseDateString(value, showTime));
Expand Down Expand Up @@ -187,7 +189,7 @@ export default function AltDateWidget<
{!options.hideNowButton && (
<Col flex="88px">
<Button block className="btn-now" onClick={handleNow} type="primary">
Now
{translateString(TranslatableString.NowLabel)}
</Button>
</Col>
)}
Expand All @@ -200,7 +202,7 @@ export default function AltDateWidget<
onClick={handleClear}
type="primary"
>
Clear
{translateString(TranslatableString.ClearLabel)}
</Button>
</Col>
)}
Expand Down
14 changes: 6 additions & 8 deletions packages/antd/test/__snapshots__/Form.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1982,19 +1982,17 @@ exports[`single fields unsupported field 1`] = `
className="unsupported-field"
>
<p>
Unsupported field schema
<span>
for
field
Unsupported field schema for field
<code>
root
</code>
</span>
<em>
:
Unknown field type undefined
</em>
.
<em>
Unknown field type undefined
</em>
.
</span>
</p>
<pre>
{}
Expand Down
4 changes: 3 additions & 1 deletion packages/bootstrap-4/src/AddButton/AddButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
IconButtonProps,
RJSFSchema,
StrictRJSFSchema,
TranslatableString,
} from "@rjsf/utils";
import Button from "react-bootstrap/Button";
import { BsPlus } from "@react-icons/all-files/bs/BsPlus";
Expand All @@ -13,12 +14,13 @@ export default function AddButton<
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>({ uiSchema, registry, ...props }: IconButtonProps<T, S, F>) {
const { translateString } = registry;
return (
<Button
{...props}
style={{ width: "100%" }}
className={`ml-1 ${props.className}`}
title="Add Item"
title={translateString(TranslatableString.AddItemButton)}
>
<BsPlus />
</Button>
Expand Down
8 changes: 6 additions & 2 deletions packages/bootstrap-4/src/ErrorList/ErrorList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@ import {
FormContextType,
RJSFSchema,
StrictRJSFSchema,
TranslatableString,
} from "@rjsf/utils";

export default function ErrorList<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>({ errors }: ErrorListProps<T, S, F>) {
>({ errors, registry }: ErrorListProps<T, S, F>) {
const { translateString } = registry;
return (
<Card border="danger" className="mb-4">
<Card.Header className="alert-danger">Errors</Card.Header>
<Card.Header className="alert-danger">
{translateString(TranslatableString.ErrorsLabel)}
</Card.Header>
<Card.Body className="p-0">
<ListGroup>
{errors.map((error, i: number) => {
Expand Down
26 changes: 23 additions & 3 deletions packages/bootstrap-4/src/IconButton/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
IconButtonProps,
RJSFSchema,
StrictRJSFSchema,
TranslatableString,
} from "@rjsf/utils";
import Button, { ButtonProps } from "react-bootstrap/Button";
import { IoIosRemove } from "@react-icons/all-files/io/IoIosRemove";
Expand Down Expand Up @@ -34,8 +35,15 @@ export function MoveDownButton<
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: IconButtonProps<T, S, F>) {
const {
registry: { translateString },
} = props;
return (
<IconButton title="Move down" {...props} icon={<AiOutlineArrowDown />} />
<IconButton
title={translateString(TranslatableString.MoveDownButton)}
{...props}
icon={<AiOutlineArrowDown />}
/>
);
}

Expand All @@ -44,17 +52,29 @@ export function MoveUpButton<
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: IconButtonProps<T, S, F>) {
return <IconButton title="Move up" {...props} icon={<AiOutlineArrowUp />} />;
const {
registry: { translateString },
} = props;
return (
<IconButton
title={translateString(TranslatableString.MoveUpButton)}
{...props}
icon={<AiOutlineArrowUp />}
/>
);
}

export function RemoveButton<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: IconButtonProps<T, S, F>) {
const {
registry: { translateString },
} = props;
return (
<IconButton
title="Remove"
title={translateString(TranslatableString.RemoveButton)}
{...props}
variant="danger"
icon={<IoIosRemove />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
FormContextType,
RJSFSchema,
StrictRJSFSchema,
TranslatableString,
WrapIfAdditionalTemplateProps,
} from "@rjsf/utils";

Expand All @@ -31,9 +32,10 @@ export default function WrapIfAdditionalTemplate<
uiSchema,
registry,
}: WrapIfAdditionalTemplateProps<T, S, F>) {
const { templates, translateString } = registry;
// Button templates are not overridden in the uiSchema
const { RemoveButton } = registry.templates.ButtonTemplates;
const keyLabel = `${label} Key`; // i18n ?
const { RemoveButton } = templates.ButtonTemplates;
const keyLabel = translateString(TranslatableString.KeyLabel, [label]);
const additional = ADDITIONAL_PROPERTY_FLAG in schema;

if (!additional) {
Expand Down
14 changes: 6 additions & 8 deletions packages/bootstrap-4/test/__snapshots__/Form.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1597,19 +1597,17 @@ exports[`single fields unsupported field 1`] = `
className="unsupported-field"
>
<p>
Unsupported field schema
<span>
for
field
Unsupported field schema for field
<code>
root
</code>
</span>
<em>
:
Unknown field type undefined
</em>
.
<em>
Unknown field type undefined
</em>
.
</span>
</p>
<pre>
{}
Expand Down
8 changes: 7 additions & 1 deletion packages/bootstrap-4/test/helpers/createMocks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { createSchemaUtils, WidgetProps, RJSFSchema } from "@rjsf/utils";
import {
createSchemaUtils,
englishStringTranslator,
WidgetProps,
RJSFSchema,
} from "@rjsf/utils";
import { getDefaultRegistry } from "@rjsf/core";
import validator from "@rjsf/validator-ajv8";

Expand All @@ -24,6 +29,7 @@ export function mockRegistry() {
formContext: {},
rootSchema: {},
schemaUtils: mockSchemaUtils,
translateString: englishStringTranslator,
};
}

Expand Down
Loading

0 comments on commit d7919a8

Please sign in to comment.