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?
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.
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.
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.
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";
}
}
}
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?
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 :
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.
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.
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)then a function to go through the content (and recurse down the tree)
Then you have a function to go through all the properties
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
An interesting solution but in the course I get an exception System.StackOverflowException
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 passchildItem
notItem
sorryThanks 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); } }
hi
you will need to include a call to contentService.Save() to push the changes back into the DB.
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); }
Cool,
you can simplify some of that code with a call to
SaveAndPublishWithStatus
which will save and publish the page in one go.K
is working on a reply...