Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Eugen 30 posts 131 karma points
    Nov 29, 2018 @ 15:59
    Eugen
    0

    Translation through database in Umbraco CMS

    Hello. I am new in UmbrakoCMS. I am developing a plugin that translates content by translating field 'DataNtext' in a database table 'CmsPropertyData'. For verification, I open the file Umbraco.sdf and there really is a translated value. But in practice, the content is not translated. Still remained in the same language. Someone can tell why so?

  • Kevin Jump 2311 posts 14696 karma points MVP 7x c-trib
    Nov 29, 2018 @ 18:01
    Kevin Jump
    0

    Hi Eugen,

    Going direct to the content in umbraco is going to cause you quite a lot of issues, there are many layers of caching in umbraco and that is why i think you won't see any changes to content when you just update the DB.

    The integrity of the content in the database is maintained by the umbraco business layer and by bypassing that you are also likely to run into issues with content going missing or whole bits of the structure of your site getting corrupt.

    It is safer to use the ContentService to get stuff in and out of the database and use the SetValue / GetValue properties on a IContentItem to read the values of the content -

    so at a basic level :

    var node = contentService.GetById(id);
    var content = node.GetValue<string>("propertyName");
    // do stuff
    node.SetValue("propertyName", content);
    contentService.Save(node);
    

    Saving content this way will flush any caches and keep the history and audit trails umbraco keeps for content while also maintaining the integrity of the content types, and content relationships.

    but along with all that, there is a package managing translations in umbraco - Translation Manager (Disclaimer i did write this!) will extract the content from the umbraco site, and allows you to pass it over to other services in things like the standard translation Xliff format - it also comes with providers that will do things like automatic translations via microsoft or google. This package may save you quite a bit of time, in terms of doing all the heavy lifting at the umbraco content end.

  • Eugen 30 posts 131 karma points
    Nov 30, 2018 @ 07:08
    Eugen
    0

    Thank you so much for the answer. Can you please tell me how to loop through all the content? I have a function that accepts a string and returns it already translated. So, I want to translate all the content.

  • Kevin Jump 2311 posts 14696 karma points MVP 7x c-trib
    Nov 30, 2018 @ 09:18
    Kevin Jump
    1

    Hi Eugene,

    all the content as in all of the content on a site ?

    below is the pseudo code for that, but it can get complicated at the end - when you have to start working out what properties contain text and where it might be inside properties that can be nested or in json fragments.

    so using the ContentService (assuming you have it as a variable contentService in your class somewhere)

    foreach(var item in contentService.GetRootContent())
    {
        // recurse into each item
        ProcessContentItem(item);
    }
    

    then a function to go through the content (and recurse down the tree)

    private void ProcessContentItem(IContent item) {
       // handle the properties
       TranslateProperties(item)
    
       foreach (var childItem in contentService.GetChildren(item.Id))
       {
           ProcessContentItem(item);
       }
    }
    

    Then you have a function to go through all the properties

     private void TranslateProperties(IContent item)
     {
        foreach(var property in item.Properties) 
        {
           // 1. work out if this property is one you want to translate 
           //      e.g. does it contain text or is it a picker or numbers 
    
           //  2. extract the text part of the property (if this is something
                    like the grid or nested content the data will be stored in json
                    so you will have to extract that, and then recurse into the 
                    json to work out if there is any text in there) 
    
            // 3. do your translation bit 
    
            // 4. put the translated text back into the property (reversing
                    anything you did when you extracted the text from complex
                    things in step 2)
       }
    }
    

    The complicated thing are step 2 and 4 - if your site uses anything beyond standard textboxs for the content, you are likely to have the content stored within json within the properties, these bits of json will vary depending on the data type used (e.g the grid, or nested content or archetype to name a few).

    In your code you will need to go into this json, and potentially recurse down it looking at the properties within that to see if they are text or links or something else (like an image) - then you will need to extract the text from the right point in the json, and in step 4 once you've translated it put it back in the right place without breaking the json configuration that may already be there.

    or - final plug i swear :) - Translation Manager will do all of the above steps for you and if you needed to you could write a provider for it that would have to just do step 3.

    Kevin

  • Eugen 30 posts 131 karma points
    Dec 04, 2018 @ 12:17
    Eugen
    0

    An interesting solution but in the course I get an exception System.StackOverflowException

  • Kevin Jump 2311 posts 14696 karma points MVP 7x c-trib
    Dec 04, 2018 @ 13:10
    Kevin Jump
    1

    yeah sorry,

    there is an error in that code (in my defence i did just type it into the comments box ;-) )

    internal call to ProcessContentItem, should pass childItem not Item sorry

    private void ProcessContentItem(IContent item) {
       // handle the properties
       TranslateProperties(item)
    
       foreach (var childItem in contentService.GetChildren(item.Id))
       {
           ProcessContentItem(childItem);
       }
    }
    
  • Eugen 30 posts 131 karma points
    Dec 04, 2018 @ 13:19
    Eugen
    0

    Thanks for the help anyway, but unfortunately nothing came of it. I bring my test implementation. Unfortunately, the changes are not saved.

    protected void Button1_Click(object sender, EventArgs e) {
    IContentService contentService = ApplicationContext.Current.Services.ContentService; foreach (var item in contentService.GetRootContent()) { ProcessContentItem(item); item.ChangePublishedState(PublishedState.Saved); item.ChangePublishedState(PublishedState.Published); } }

        private void ProcessContentItem(IContent item)
        {
            IContentService contentService = ApplicationContext.Current.Services.ContentService;        
            TranslateProperties(item);
    
            foreach (var childItem in contentService.GetChildren(item.Id))
            {               
                ProcessContentItem(childItem);
                childItem.ChangePublishedState(PublishedState.Saved);
                childItem.ChangePublishedState(PublishedState.Published);
            }
            item.ChangePublishedState(PublishedState.Saved);
            item.ChangePublishedState(PublishedState.Published);
        }
        //непосредственно перевод всех свойств
        private void TranslateProperties(IContent item)
        {
            Translator trans = new Translator();
            foreach (var property in item.Properties)
            {
                bool flag = true;
                if (property.Value == null)
                    continue;
                string str = property.Value.ToString();
                if (str.StartsWith("umb://"))
                {
                    flag = false;
                }
                if (str.StartsWith("{ \"name\""))
                {
                    flag = false;
                }
                if (str.StartsWith("{\"name\""))
                {
                    flag = false;
                }
                if (str.StartsWith("{ \"zoom\""))
                {
                    flag = false;
                }
                if (str.StartsWith("/media"))
                {
                    flag = false;
                }
                if (str.StartsWith("[{"))
                {
                    flag = false;
                }
                if (str.StartsWith("{\n"))
                {
                    flag = false;
                }
                if (str.StartsWith("{\\"))
                {
                    flag = false;
                }
                if (str.StartsWith("{\r\n"))
                {
                    flag = false;
                }
                var isNumeric = int.TryParse(str, out var n);
                if (flag && str != string.Empty && !isNumeric)
                {                   
                    property.Value = "TEST";                    
                }
            }
        }
    
  • Kevin Jump 2311 posts 14696 karma points MVP 7x c-trib
    Dec 04, 2018 @ 13:36
    Kevin Jump
    100

    hi

    you will need to include a call to contentService.Save() to push the changes back into the DB.

  • Eugen 30 posts 131 karma points
    Dec 04, 2018 @ 13:43
    Eugen
    0

    You are wonderful. It worked. For the rest, I'll add that I changed two methods and it all worked as it should.

    foreach (var childItem in contentService.GetChildren(item.Id)) {
    ProcessContentItem(childItem); contentService.Save(childItem); contentService.Publish(childItem); childItem.ChangePublishedState(PublishedState.Saved); childItem.ChangePublishedState(PublishedState.Published); }

    foreach (var item in contentService.GetRootContent()) { ProcessContentItem(item); contentService.Save(item); contentService.Publish(item); }

  • Kevin Jump 2311 posts 14696 karma points MVP 7x c-trib
    Dec 04, 2018 @ 13:46
    Kevin Jump
    1

    Cool,

    you can simplify some of that code with a call to SaveAndPublishWithStatus which will save and publish the page in one go.

    K

Please Sign in or register to post replies

Write your reply to:

Draft