Adding field localization later to the model

Hey!

I found an issue, with custom field level localization.

Currently my data model does not support localization, here is the model:


And I have my entry with my data:

Now, I have decided that I will add localization to this field, already added my locales and now I want to enable custom field localization.


(custom targeting)

So I will switch the toggle in the model:

And when I go back to my model, it will overrides my previous data:


Which is very unexpected, because if I want to change all of my model’s field to localized, then all of my entry data will be removed from there.

It would be great, and expected, that the current field’s content would stay in the default locale value, something like this: (Or would store the current values in the first locale field or something like that, I just demonstrated with the default ‘en’ value this approach)

Please make this feature available as soon as possible, because we are in growth plan, and now would like to change all my fields with localization, without losing weeks of work with our models and entries.

Please let me know!
@steve @TimG @maddy

1 Like

That would be a nice thing to have!

Hi @radikris thanks for this, I agree this user experience can probably be improved…as you know the field level localization is still in beta, so there are some kinks to still work through.

I will file a ticket with our dev team and keep you posted! In the meantime, if you set a field to be localized, I would recommend copying the default text somewhere to be pasted after the toggle as a work around.

Thanks for the heads up, we always appreciate our users’ feedback!

Yes, that’s a possible workaround, but with too much headache, if we have ca 150 entry currently. Please if you can, speed up this process with the dev team, hope we can make this happen in a short time, because it is not too difficult feature request.
Let me know!
Thanks @TimG

I just noticed, if I toggle the switch back:
My default data will be restored, although last time it has been vanished. (I thought the system will override it, but luckily no!)

So I guess the model will store my data still, only not showing up, so in my opinion the solution is pretty easy because the data is there, but if the user enables localization some new properties will be added to the model, and you just have to pass to the list[0] item the current stored data.

Hope it helped, and you can make this feature happen asap! :slight_smile:

@TimG any update on this?

@radikris dev team is aware and it is in our horizon but it is difficult to give a hard timeframe at this time. Will keep you posted !

any update on this @TimG ? I saw that for eg simple text will be placed after localization to the default, but richtext, image etc more complex input fields won’t be, and they disappear (still visible in the json view, but only as a simple field, not the localized version)

Hey @radikris, I just checked this and confirmed it does seem to not work as intended for complex inputs. I will raise a ticket and check with our dev team

Thank you, and also mention please, that if I already localized a model, but these inputs not saved to the default entry, (but did not change anything) would be great, if these fields would appear too, not only those which will be localized after your update

(hope you understand, that I don’t want to make this for those models which we already localized, but not working right now)

Hello Tim, can you please tell us an about date, deadline when can you fix this issue? Our production app deployment depends on this feature strongly, because if we have to manually copy paste the unlocalized values from the jsonview to the localized inputs it increases the worktime tremendously.

I know the team has a lot to do, and you are doing great, but can you please urge this ticket to your dev team please, as a Growth customer we hope we can rely on your commitment, and we can stay in strong connection later on as well. Hope you understand my concerns, and we can make this happen as soon as possible!

Thank you very much in advance!
Best wishes,
Kristof

@TimG , @steve please any update?

Hi @radikris I appreciate your patience on this!

I checked with our product team last week, and considering this is still a beta feature and that this feature request is a convenience improvement, there is currently no set timeline on adding support for image, richtext, etc default update at this time. It is definitely in our backlog and on our radar though.

I was waiting to follow up with one more person before replying to you, to see if there was a slight chance that there was some part of this that was an easy lift to add, but I will have to get back to you on Monday with that.

As a work around, if you do start localizing after the fact and we still do not have this feature, I think you could possibly write a script to copy down your data with the Query API, then you set the fields to be localized, and use another script based on the Write API to input the previous defaults. Do you think that could be a possible solution? I am happy to work with you on that as needed.

Again, I really appreciate your patience and we appreciate all your feedback in helping beta test our new localization features!! We will be sure to follow up shortly!

Thanks for your response @TimG!

For a workaround it sounds reasonable, but of course would be better if it would work out of the box.
To be honest, I am not very experienced in the Write API-s, if you could provide a demo example or loom video how you do it in a demo model, I would really appreciate it, and I will try to follow along these tutorial and after that do it myself, is it acceptable for you?

Hey @radikris definitely, so in order to update an existing field in the write API, you simply do a PATCH request to our write API url with the content updates required. This will merge your changes into the existing content entry, so you wont need to update ALL fields.

Essentially, you would be doing something similar to what is outlined in this forum post: How to rename a field in a model and all its content retroactively

Let’s say you have blog articles with a custom field called localizedImage that we want to localize.

// read all result  might need to paginate if list > 100
const allContent = await fetch('https//builder.io/api/v2/content/blog-article?apiKey=${YOUR_API_KEY&}fields=data.localizedImage')
  .then(res => res.json());

This will give you all of the content entries for a given model you want to update, and only the localizedImage field. The results should look something like this:

{
  "results": [
    {
      "name": "blog article name",
      "data": {
        "localizedImage": "https://cdn.builder.io/api/v1/image/assets%2Fe37b966ec695434bb21e97442a4a9f46%2F04380702c8814b88af95b9efa5ffb063"
      }
    },
    {
      "name": "another blog article",
      "data": {
        "localizedImage": "https://cdn.builder.io/api/v1/image/assets%2Fe37b966ec695434bb21e97442a4a9f46%2Fa52c091476ff44eabb3da9dedb6948e1"
    },
   ...
  ]
}

Once you have fetched them, you can map over them and update the content you want

allContent.results.map(entry =>  {
//grab the current image
 const originalDefault = entry.data.localizedImage; 
//update the entry to be localized
  entry.data.localizedImage = {
          "@type": "@builder.io/core:LocalizedValue",
          "Default": originalDefault, 
          "en": someEnValue, //you can even update the localized values now if you want
          "hu": someHuValue, 
           ...
        }
  await fetch('https://builder.io/api/v2/write/blog-model', {
   method: 'PATCH',
   headers: {
     Authorization: `bearer ${privateKey}`,
    },
    body: JSON.strinigify(entry),
  })
})

You will need to update the model to have the entry be localized, but that should work. You can pull down the content with the first GET request, then update the model in your Builder space and then map over content and push up with the PATCH request, OR, you should be able to update the model after the fact, but it might momentarily look wonky on your Builder UI. I recommend testing both methods to find which works best for you

I would also recommend you play around with our API Explorer to make sure you have the object shape exactly correct, as well as only working with one entry at a time to test.

Test it out and let me know if that works or you have any further questions !

Just as an example, in the API Explorer, you’d be able to see that an unlocalized content field looks like this:

{
  "results": [
    {
      "name": "blog article name",
      "data": {
        "localizedImage": "https://cdn.builder.io/api/v1/image/assets%2Fe37b966ec695434bb21e97442a4a9f46%2F04380702c8814b88af95b9efa5ffb063"
      }
    }
  ]
}

While the localized version looks like this:

{
  "results": [
    {
      "id": "dccc48821a1648b0848861eada0c72ee",
      "name": "blog article testing",
      "data": {
        "localizedImage": {
          "@type": "@builder.io/core:LocalizedValue",
          "Default": "https://cdn.builder.io/api/v1/image/assets%2Fe37b966ec695434bb21e97442a4a9f46%2Fa1daf58e0e944ae6abc1bf2c9fd1b885",
          "en-CA": "https://cdn.builder.io/api/v1/image/assets%2Fe37b966ec695434bb21e97442a4a9f46%2F1d27bc748a1143808c9feefbe2dfe536",
          "en-US": "https://cdn.builder.io/api/v1/image/assets%2Fe37b966ec695434bb21e97442a4a9f46%2Fa52c091476ff44eabb3da9dedb6948e1",
          "es-US": "https://cdn.builder.io/api/v1/image/assets%2Fe37b966ec695434bb21e97442a4a9f46%2F04380702c8814b88af95b9efa5ffb063"
        }
      }
    }
  ]
}

So you can make sure you build your new content object in the correct way…its a very helpful tool and I use it all the time when testing out things with our APIs!

Thank you very much @TimG for your detailed response, I will take a look on this, and will let you know how it turns out, but it looks great at the first glance.

1 Like

@TimG I just sent you an email with my problem, please check that out.

I will leave the main issue here:

Code:

#!/usr/bin/node
import fetch from "node-fetch";

const privateKey = "PRIVATEKEY";
const runScript = async () => {

  const allContent = await fetch(
    "https://cdn.builder.io/api/v2/content/localizemodelexample?apiKey=32f148657e2646be8562eb4e6ebfa190&limit=1&fields=data.title,data.description"
  ).then((res) => res.json());

  allContent.results.map(async (entry) => {
    //grab the current image
    console.log(entry);
    const originalDefaultTitle = entry.data.title.Default;
    const originalDefaultDescription = entry.data.description;
    //update the entry to be localized
    entry.data.title = {
      "@type": "@builder.io/core:LocalizedValue",
      Default: originalDefaultTitle,
      en: originalDefaultTitle,
      hu: originalDefaultTitle,
      de: originalDefaultTitle,
      sl: originalDefaultTitle,
      cz: originalDefaultTitle,
    };
    entry.data.description = {
      "@type": "@builder.io/core:LocalizedValue",
      Default: originalDefaultDescription,
      en: originalDefaultDescription,
      hu: originalDefaultDescription,
      de: originalDefaultDescription,
      sl: originalDefaultDescription,
      cz: originalDefaultDescription,
    };
    console.log(entry);
    const result = await fetch(
      "https://builder.io/api/v2/write/localizemodelexample",
      {
        method: "PATCH",
        headers: {
          Authorization: `Bearer ${privateKey}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify(entry),
      }
    )
      .then(function (response) {
        console.log(response);
        return response;
      })
      .catch((e) => {
        console.log(e);
      });
  });
};

runScript();

The get request:
https://cdn.builder.io/api/v2/content/localizemodelexample?apiKey=32f148657e2646be8562eb4e6ebfa190&limit=1&fields=data.title,data.description

{
   "results":[
      {
         "data":{
            "title":{
               "Default":"test333"
            },
            "description":"<p><sub style=\"vertical-align: sub; font-size: smaller; color: rgb(255, 153, 0); background-color: rgb(0, 0, 0);\"><strong>Alma körte szia333333</strong></sub></p>"
         }
      }
   ]
}

And also turned on the localized value:
image.png

image.png

Here you can see the result. I don’t know why is it not working.
The result not visible in the visual editor:

Can you please help me to solve this problem?

Ok, @TimG answer was not 100% correct this time.

 const result = await fetch(
      `https://builder.io/api/v1/write/localizemodelexample/${entry.id}`,
      {
        method: "PATCH",
        headers: {
          Authorization: `Bearer ${privateKey}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify(entry),
      }
    )

This is how I solved it, with api v1, and passing the id in the query.