Can't translate Autocomplete options (use mui) in custom renderer

I need your help! I’ve create custom renderer for Autocomplete control using Unwrapped, to throw my options from backend to your MaterialEnumControl, not from schema. It works! But it didn’t see translations keys in my i18n.json. I’ve read docs, but I couldn’t understand how to use it.

My custom renderer

import React, { useEffect, useMemo, useState } from 'react';
import { ControlProps, EnumOption, OwnPropsOfEnum } from '@jsonforms/core';
import {
  withJsonFormsControlProps,
  useJsonForms,
  withTranslateProps,
  TranslateProps,
  JsonFormsStateContext,
} from '@jsonforms/react';
import { Unwrapped } from '@jsonforms/material-renderers';
import { IObject } from '@Interfaces';
import { WithOptionLabel } from '@jsonforms/material-renderers/lib/mui-controls/MuiAutocomplete';

const { MaterialEnumControl } = Unwrapped;

const RealEstateTypeControl = (
  props: ControlProps & OwnPropsOfEnum & TranslateProps & WithOptionLabel,
) => {
  const { realEstateTypesData } = props.config;
  const { locale, translate } = useJsonForms().i18n as JsonFormsStateContext;
  const { data: contextData } = useJsonForms().core as JsonFormsStateContext;
  const currentCategory = contextData?.realEstateCategory;
  const currentSubcategory = contextData?.realEstateSubcategory;

  const enumOptions = useMemo(
    () => getRealEstateTypes(realEstateTypesData, currentCategory, currentSubcategory),
    [currentCategory, currentSubcategory],
  );

  return <MaterialEnumControl {...props} options={enumOptions} />;
};

export default withJsonFormsControlProps(withTranslateProps(RealEstateTypeControl));

Here I filter my data from backend

const getRealEstateTypes = (data: IObject[], category: string, subcategory?: string) => {
  let enumOptions: EnumOption[] = [];

  let filteredValues = data.filter(
    ({ category: itemCategory, subcategory: itemSubcategory }) =>
      category === itemCategory && subcategory === itemSubcategory,
  );

  if (filteredValues?.length) {
    enumOptions = filteredValues.map(({ label }) => {
      return {
        label,
        value: label,
      };
    });
    return enumOptions;
  }

  filteredValues = data.filter(({ category: itemCategory }) => category === itemCategory);

  if (filteredValues?.length) {
    enumOptions = filteredValues.map(({ label }) => {
      return {
        label,
        value: label,
      };
    });
    return enumOptions;
  }

  return [];
};

This is example of data from backend. first two elements has labels with keys for translation.

export const realEstateTypesData = [
  { id: 1, label: 'apartment', category: 'housing_stock' },
  { id: 2, label: 'studio_apartment', category: 'housing_stock' },
  { id: 3, label: 'Кімната', category: 'housing_stock' },
  { id: 4, label: 'Будинок', category: 'housing_stock' },
  { id: 5, label: 'Частина будинку', category: 'housing_stock' },
  { id: 6, label: 'Дача', category: 'housing_stock' },
  { id: 7, label: 'Таунхаус', category: 'housing_stock' },
  {
    id: 8,
    label: 'бізнес-центр',
    category: 'commerce',
    subcategory: 'office_rooms',
  },

My i18n.json

{
  "ua": {
    "realEstateType.label": "Тип нерухомості",
    "realEstateType.apartment": "Квартира",
    "realEstateType.studio_apartment": "Квартира-студія"
   },
 "pl": {...... the same keys}

and schema.json for this part

"schema": {
    "type": "object",
    "properties": {
     "realEstateCategory": {
        "type": "string",
        "title": "Категорія нерухомості",
        "enum": ["housing_stock", "commerce", "land", "garages"]
      },
      "realEstateSubcategory": {
        "type": "string",
        "title": "Категорія комерційної нерухомості",
        "enum": [
          "office_rooms",
          "office_buildings",
          "retail_space",
          "storage_facilities",
          "production_facilities",
          "rest",
          "premises_free_of_destination",
          "business_for_sale"
        ]
      },
      "realEstateType": {
        "type": "string",
        "title": "realty_type"
      },
    }

Custom Renderer was created for field “realEstateType” in schema
Maybe I’m doing something wrong?

Hi @Natatashkin,

As you manage the enum for yourself you also need to manage the translations yourself. The enumOptions you hand over to the MaterialEnumControl already need to be translated.

I see that you are consuming the TranslateProps, so you already have the locale and translator t available in your props. So after determining the enumOptions you could translate them, for example like this:

const i18nEnumOptions = useMemo(
  () => enumOptions.map(option => ({...option, label: props.t(option.label, option.label)}), 
  [enumOptions, props.t]
);

Don’t forget to also hand in a proper i18n.translate to the JSON Forms root component. That translate function can consume your i18n.json and then perform the appropriate translations. For more information see here.

1 Like

It works, with a little fix for i18n.json. I discovered that only in this custom renderer, function cteateTanslate does’n define keys such as “realEstateType.apartment”. I fixed to “apartment” only and now it work with your method.

const translations: Record<string, Record<string, string>> = i18n;

createTranslator function:
const createTranslator = (locale: string) => (key: string, defaultMessage?: string) => {
  console.log(key);

  return translations[locale][key] ?? defaultMessage;
};

export default createTranslator;

New i18n.json

{
  "ua": {
    "realEstateType.label": "Тип нерухомості",
    "apartment": "Квартира",
    "studio_apartment": "Квартира-студія"
   },
 "pl": {...... the same keys}

or I can manualy add property title key to translate funstion. In that case I can use old translation keys with dot.

const i18nEnumOptions = useMemo(() => {
    return enumOptions.map((option) => {
      const translationKey = `realEstateType.${option.label}`;
      return {
        ...option,
        label: props.t(translationKey, translationKey),
      };
    });
  }, [enumOptions, props.t]);

Many thanks for the help! I really like how the schema works and how well you presented the documentation :+1: