LString is a big joke
Hi,
I begin to be really irritated. LString is a base type of Sitefinity API and used for translation.
Almost 10 months since the release and a base type doesn't really work (see attachment).......
Then 4.2 is the better version of Sitefinity but before adding tools like e-commerce. It would have been more smart to stabilize API, and to finish implementing base type.
Regards,
Nicolas
I up my post with a complement.
List of methods who doesn't worked :
- Lstring.SetCurrentLanguage(CultureInfo, bool)
- Lstring.GetString(CultureInfo, bool)
- Lstring.GetStringNoFallback(CultureInfo)
- Lstring.GetAllValues()
Hello Nicolas,
About your first posting and the CurrentLanguage property- i really have to agree that it brings a certain amount of misunderstanding. This property actually takes effect only when you set the Value of an Lstring object - so the setter actually sets the value of the culture that is in CurrentLanguage. By default it is set to the current thread UI culture. If you want to be sure what culture you are setting you can use the public void SetString(CultureInfo culture, string value) method.
The Lstring.Value property getter actually returns the string value for the current thread UI culture => System.Globalization.CultureInfo.CurrentUICulture and the getter doesn't consider the CurrentLanguage property. We will most probably hide the CurrentLanguage property in next versions since it is really confusing.
About your second posting:
Can you please clarify what "doesn't work" means:
For example Lstring.GetString(CultureInfo, bool)
=> doens't return the correct value for french or
Lstring.GetAllValues()
doens't return any values or ?
Lstring.GetStringNoFallback(CultureInfo) => crashes??
Looking forward for more details
Nikolay Datchev
the Telerik team
Hi Nikolay,
Quote :
If you want to be sure what culture you are setting you can use the public void SetString(CultureInfo culture, string value) method.
ntArticle.Title =
new
Lstring();
ntArticle
.Title.SetString(
new
CultureInfo(
"en"
),
"Lawyer SEGL/JUR/CIB/GLF/CNR"
);
ntArticle
.Title.SetString(
new
CultureInfo(
"fr"
),
"Juriste SEGL/JUR/CIB/GLF/CNR"
);
ntArticle.GetString(
new
CultureInfo(
"en"
),
true
)
"Juriste SEGL/JUR/CIB/GLF/CNR"
(French Trad).ntArticle.GetAllValues(
)
ntArticle.GetStringNoFallback(new
CultureInfo(
"en"
)
)
Hi Nicolas,
It looks like the problem is in the way you construct the Lstring instance. It should actually be constructed with a reference to your content item. So it should be initalized with
ntArticle.Title = ntArticle
.GetString("Title")
GetString is an extension method in
Telerik.Sitefinity.Model.DataExtensions
public static Lstring GetString(this IDynamicFieldsContainer dataItem, string fieldName)
Even better approach is to have your Title property implemented like this:
[DataMember] [Sortable] [CommonProperty]
[UserFriendlyDataType(UserFriendlyDataType.ShortText)]
public virtual Lstring Title
get
if (this.title == null)
this.title = this.GetString("Title");
return this.title;
set
this.title = value;
this.SetString("Title", this.title);
Hi Nikolay,
I still have a question on Lstring for NewsItem.
I previously made a ticket, but "solution" doesn't worked now on 4.2 SP1.
My problem is the Lstring Content field on NewsItem.
Previously for editing it in differents languages we have to made this :
NewsManager nMng = NewsManager.GetManager();
NewsItem sfNewsMaster = nMng.CreateNewsItem();
sfNewsMaster = nMng.Lifecycle.GetMaster(sfNewsMaster)
as
NewsItem;
NewsItem sfNews = nMng.Lifecycle.CheckOut(sfNewsMaster)
as
NewsItem;
.......
.......
Guid newsID = Guid.Empty;
foreach
(CultureInfo cultLang
in
ntArticle.Languages)
if
(newsID != Guid.Empty)
sfNewsMaster = nMng.GetNewsItem(newsID);
sfNewsMaster = nMng.Lifecycle.GetMaster(sfNewsMaster)
as
NewsItem;
sfNews = nMng.Lifecycle.CheckOut(sfNewsMaster)
as
NewsItem;
sfNews.Title.SetString(cultLang, ntArticle.Title.GetString(cultLang));
sfNews.GetString(
"Content"
)[cultLang] = ntArticle.RichTextContent.GetString(cultLang);
sfNews.ApprovalWorkflowState.SetString(cultLang,
"Published"
);
sfNewsMaster = nMng.Lifecycle.CheckIn(sfNews)
as
NewsItem;
nMng.RecompileItemUrls<NewsItem>(sfNewsMaster);
nMng.Lifecycle.PublishWithSpecificDate(sfNewsMaster, ntArticle.PublishedDate, cultLang);
try
newsID = sfNewsMaster.Id;
nMng.SaveChanges();
catch
(Exception ex)
break
;
Hello Nicolas,
Can you elaborate on this "But now the only result I got with this, it's one language for "Content" NewsItem"
Do you mean that you expect all language values to be copied ,since the code you pasted here is copying just one language. Also when you say the standard SetString doesn't work
do you mean,that the following statement doesn't work:
"Content" ntArticle.RichTextContent.GetString(cultLang), cultLang)
-> aHi,
I made a foreach on CultureInfo so it's multiple languages.
I said SetString doesn't work because if I made this :
sfNews.Content.SetString(cultLang
, ntArticle.RichTextContent.GetString(cultLang));
The news content doesn't fill in any language.
sfNews.SetString(
"Content"
, ntArticle.RichTextContent.GetString(cultLang), cultLang);
Hi Nicolas,
You actualy hit another undocumented behaviour of the Content property. This property actually doens't return the original Lstring but a filtered Lstring which has some filters applied so any links (kept as Id's) inside the Html are resolved to real Urls. The problem is that this filter is applied only on the current culture and the lstring that you get actually has only the current culture. We are thinking to fix this inconsistent behaviour in some of the next versions.
The proper way to inspect the real status of the Content property is by calling item.GetString("Content") -this returns the real Lstring without those filters applied. This is something specific for the Content property, and for example for Title you don't have such problem, since we don't do resolving there.
Also please don't look at the cultureValues[] array, to inspect what is copied and what not - test with :
item.GetString("Content")["fr"] -> check what this returns.
Basically a call like this copies all cutlures from one item to another
news1.GetString("Content").CopyTo(news2.GetString("Content"))
in your case it can be
ntArticle.RichTextContent.CopyTo(news2.GetString("Content"));
and this can be done once before the for iteration.
Also this works ok:
news2.SetString("Content","french2","fr")
just that in order to test if it worked you have to call:
news2.GetString("Content")["fr"]
not news2.Content["fr"]
Again this is valid just for the Content proeprty - because we apply those "nasty" filters there - for title and the others it should be ok to work directly with the Property
Hi,
ok gotcha. There is a trick for made it work.
Originally I worked on "Temp" NewsItem of "Master" like this :
NewsManager nMng = NewsManager.GetManager();
NewsItem sfNewsMaster = nMng.CreateNewsItem();
sfNewsMaster = nMng.Lifecycle.GetMaster(sfNewsMaster)
as
NewsItem;
NewsItem sfNews = nMng.Lifecycle.CheckOut(sfNewsMaster)
as
NewsItem;
.........
Guid newsID = Guid.Empty;
foreach
(CultureInfo cultLang
in
ntArticle.Languages)
if
(newsID != Guid.Empty)
sfNewsMaster = nMng.GetNewsItem(newsID);
sfNewsMaster = nMng.Lifecycle.GetMaster(sfNewsMaster)
as
NewsItem;
sfNews = nMng.Lifecycle.CheckOut(sfNewsMaster)
as
NewsItem;
sfNews.Title.SetString(cultLang, ntArticle.Title.GetString(cultLang));
sfNews.SetString(
"Content"
, ntArticle.RichTextContent.GetString(cultLang), cultLang);
........................
sfNews.ApprovalWorkflowState.SetString(cultLang,
"Published"
);
sfNewsMaster = nMng.Lifecycle.CheckIn(sfNews)
as
NewsItem;
nMng.RecompileItemUrls<NewsItem>(sfNewsMaster);
nMng.Lifecycle.PublishWithSpecificDate(sfNewsMaster, ntArticle.PublishedDate, cultLang);
try
newsID = sfNewsMaster.Id;
nMng.SaveChanges();
Telerik.Sitefinity.Abstractions.Log.Write(
"--- Save --- "
);
catch
(Exception ex)
Telerik.Sitefinity.Abstractions.Log.Write(
"--- News ECHEC --- "
+ ex.Message);
break
;
NewsItem sfNewsMaster = nMng.CreateNewsItem();
sfNewsMaster = nMng.Lifecycle.GetMaster(sfNewsMaster)
as
NewsItem;
NewsItem sfNews = nMng.Lifecycle.CheckOut(sfNewsMaster)
as
NewsItem;
.............
Guid newsID = Guid.Empty;
foreach
(CultureInfo cultLang
in
ntArticle.Languages)
if
(newsID != Guid.Empty)
sfNews = nMng.GetNewsItem(newsID);
sfNews.Title.SetString(cultLang, ntArticle.Title.GetString(cultLang));
sfNews.SetString(
"Content"
, ntArticle.RichTextContent.GetString(cultLang), cultLang);
...................
if
(newsID == Guid.Empty)
sfNewsMaster = nMng.Lifecycle.CheckIn(sfNews)
as
NewsItem;
nMng.RecompileItemUrls<NewsItem>(sfNewsMaster);
nMng.Lifecycle.PublishWithSpecificDate(sfNewsMaster, ntArticle.PublishedDate, cultLang);
else
nMng.RecompileItemUrls<NewsItem>(sfNews);
nMng.Lifecycle.PublishWithSpecificDate(sfNews, ntArticle.PublishedDate, cultLang);
try
newsID = sfNewsMaster.Id;
nMng.SaveChanges();
Telerik.Sitefinity.Abstractions.Log.Write(
"--- Save language : --- "
);
catch
(Exception ex)
Telerik.Sitefinity.Abstractions.Log.Write(
"--- News ECHEC --- : "
+ ex.Message);
break
;
Hello Nicolas,
I am glad you manage to make it work, i guess we can close this thread for now.
Kind regards,
Nikolay Datchev
the Telerik team
I know this is an old thread, but the topic still holds weight. Over the last year of developing with Sitefinity I've battled Lstring again and again. Just ran into another issue today where some reflection code was not mapping values, because a type check was in place and typeof(String) != typeof(Lstring). Excellent, so we have to put in a specific check just for Lstring to allow the mapping!
Why oh why did you have to expose your own custom String object Telerik? It causes far more frustration than any help it provides.
I totally agree with how tiring this is
See code
var folderList = dynamicModuleManager.GetDataItems(videoFolderType).Where(i => i.Status == ContentLifecycleStatus.Master);
if (folderList == null)
throw new NotFoundException("Embed Video Module");
var xList = folderList.Select(f => f.UrlName).ToList();
this var xList fails. And I tried f.UrlName.value, f.UrlName.ToString().
That ToString() fails with : Method 'ToString' is not supported on the 'System.Object' type. I am totally out of ideas. And this is the first hit in Google.
Good job LString.
Edit: This is what worked (see below)
List<string> retList = new List<string>();
foreach (var item in folderList)
string sad;
bool xFound = item.UrlName.TryGetValue(out sad);
if (xFound)
retList.Add(sad);
else
retList.Add("not found folder Name");
-- but .value fails with : Property 'System.String Value' is not defined for type 'System.String'.
Another one...
libraryManager.GetChildFolders( currentFolder ).FirstOrDefault( x => x.Title.TrimEnd( '-' ) == subFolderName )
is shown in intellisense, but errs out with:
Method 'TrimEnd' is not supported on the 'Telerik.Sitefinity.Model.Lstring' type.
Things like this end up costing hours of work. When I replace a common and expected type with my own, I usually inherit the base type. If this is not possible or practical, I replicate every call unless there is a compelling reason not to (in which case I document it). It is a lot of work sometimes, but makes maintenance much easier. As Lstring is replacing string, it would be nice if it included all of the normal things you can do with a string.