I'm planning to implement a multi language website, so my first ideas were to use the resx files, but I have a requirements to let every text editable from the administration,
can i do such a feature with resx files or should I store them in a database (schemaless) or is there a better way to do this?
you can use xml or sql tables.
you should prepare a page for administrator and list all the words for translate.
base of language administrator logged on , update the translation of words into your table or xml file.
additional , for best performance load each language words to system catch .
write some code like this for entering words into table or xml.
<%=PLang.GetString("YourWordInEnglish")%>
in your aspx
...................
public static string GetString(string word)
{
try
{
if (String.IsNullOrWhiteSpace(word)) return "";
Dictionary<string, string> resourcesDictionary = GetResource(GetLanguageID());
if (resourcesDictionary != null)
{
if (!resourcesDictionary.ContainsKey(word.ToLower()))
{
Expression exp = new Expression();
exp.Word = exp.Translation = word;
exp.LanguageID = GetLanguageID();
exp.SiteID = Globals.GetSiteID();
if (exp.SiteID == 0 && exp.LanguageID == 0)
return word;
if (FLClass.createExpression(exp, ref resourcesDictionary) > 0)
return resourcesDictionary[word];
else
return word;
}
return resourcesDictionary[word.ToLower()];
}
else
return word;
}
catch
{
return word;
}
}
...................
function for edit
public class ViewExpressionListEdit : BaseWebService
{
[WebMethod(EnableSession = true)]
public bool updateExpression(ExpressionService expressionService)
{
Expression expression = new Expression();
expression.ExpressionID = expressionService.ExpressionID;
expression.Translation = expressionService.Translation;
expression.LanguageID = expressionService.LanguageID;
expression.SiteID = Globals.GetSiteID();
return FLClass.updateExpression(expression);
}
}
You can use XML files for translations, parse them on application startup and store translations in cache. You can use the FileSystemWatcher class to see when someone updates the files and then invalidate the cache.
Related
my first question is here
however since I was advised that questions should not change the original matter I created a new one.
I am saving user settings and I would like to save it in the list, I have had a look on setting by James however I found that that its not possible to save it in the list. So ia have decided to use Xamarin Essentials.
First I tried to save only a string value, which after some struggle I managed to work out and now I am trying to save an object
static void AddToList(SettingField text)
{
var savedList = new List<SettingField>(Preference.SavedList);
savedList.Add(text);
Preference.SavedList = savedList;
}
private void ExecuteMultiPageCommand(bool value)
{
var recognitionProviderSettings = new RecognitionProviderSettings
{SettingFields = new List<SettingField>()};
var set = new SettingField()
{
ProviderSettingId = "test",
Value = "test"
};
AddToList(set);
NotifyPropertyChanged("IsMultiPage");
}
and then the sterilization and des
public static class Preference
{
private static SettingField _settingField;
public static List<SettingField> SavedList
{
get
{
//var savedList = Deserialize<List<string>>(Preferences.Get(nameof(SavedList), "tesr"));
var savedList = Newtonsoft.Json.JsonConvert.DeserializeObject<SettingField>(Preferences.Get(nameof(SavedList), _settingField)) ;
SavedList.Add(savedList);
return SavedList ?? new List<SettingField>();
}
set
{
var serializedList = Serialize(value);
Preferences.Set(nameof(SavedList), serializedList);
}
}
static T Deserialize<T>(string serializedObject) => JsonConvert.DeserializeObject<T>(serializedObject);
static string Serialize<T>(T objectToSerialize) => JsonConvert.SerializeObject(objectToSerialize);
}
}
But Preferences.Get doesn't take object, is there any other way how can I save my setting to a object list? Please advise
I would recommend you to use SecureStorage. You can save your strings only into it. So the place where you have serilized your object as json. Just convert your json to string with .ToString() and save it into secure storage.
You may continue saving your serialized json object as string in Shared preferences but it is recommended to use SecureStorage Instead.
I am building a VSIX package to support a custom language in Visual Studio using MPF. I am in a custom designer and I need to find the files referenced in the project to resolve some dependencies. Where can I access this list?
I assume, that you´re using MPF to implement the project system for your custom language service. When doing so, you probably have a project root node which is derived from either ProjectNode or HierarchyNode...
If so, you could share the root node´s instance with the designer and try to find files by traversing the hierarchy, for instance...
internal class HierarchyVisitor
{
private readonly Func<HierarchyNode, bool> filterCallback;
public HierarchyVisitor(
Func<HierarchyNode, bool> filter)
{
this.filterCallback = filter;
}
public IEnumerable<HierarchyNode> Visit(
HierarchyNode node)
{
var stack = new Stack<HierarchyNode>();
stack.Push(node);
while (stack.Any())
{
HierarchyNode next = stack.Pop();
if (this.filterCallback(next))
{
yield return next;
}
for (
HierarchyNode child = next.FirstChild;
child != null;
child = child.NextSibling)
{
stack.Push(child);
}
}
}
}
To get a list of all nodes in the hierarchy, you could just do...
ProjectNode root = ...
var visitor = new HierarchyVisitor(x => true);
IEnumerable<HierarchyNode> flatList = visitor.Visit(root);
Or to filter for a certain file type, you could try something like this...
ProjectNode root = ...
var visitor = new HierarchyVisitor((HierarchyNode x) =>
{
const string XmlFileExtension = ".xml";
string path = new Uri(x.Url, UriKind.Absolut).LocalPath;
return string.Compare(
XmlFileExtension,
Path.GetFileExtension(path),
StringComparison.InvariantCultureIgnoreCase) == 0;
});
IEnumerable<HierarchyNode> xmlFiles = visitor.Visit(root);
I have different plugins in my Web api project with their own XML docs, and have one centralized Help page, but the problem is that Web Api's default Help Page only supports single documentation file
new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/Documentation.xml"))
How is it possible to load config from different files? I wan to do sth like this:
new XmlDocumentationProvider("PluginsFolder/*.xml")
You can modify the installed XmlDocumentationProvider at Areas\HelpPage to do something like following:
Merge multiple Xml document files into a single one:
Example code(is missing some error checks and validation):
using System.Xml.Linq;
using System.Xml.XPath;
XDocument finalDoc = null;
foreach (string file in Directory.GetFiles(#"PluginsFolder", "*.xml"))
{
if(finalDoc == null)
{
finalDoc = XDocument.Load(File.OpenRead(file));
}
else
{
XDocument xdocAdditional = XDocument.Load(File.OpenRead(file));
finalDoc.Root.XPathSelectElement("/doc/members")
.Add(xdocAdditional.Root.XPathSelectElement("/doc/members").Elements());
}
}
// Supply the navigator that rest of the XmlDocumentationProvider code looks for
_documentNavigator = finalDoc.CreateNavigator();
Kirans solution works very well. I ended up using his approach but by creating a copy of XmlDocumentationProvider, called MultiXmlDocumentationProvider, with an altered constructor:
public MultiXmlDocumentationProvider(string xmlDocFilesPath)
{
XDocument finalDoc = null;
foreach (string file in Directory.GetFiles(xmlDocFilesPath, "*.xml"))
{
using (var fileStream = File.OpenRead(file))
{
if (finalDoc == null)
{
finalDoc = XDocument.Load(fileStream);
}
else
{
XDocument xdocAdditional = XDocument.Load(fileStream);
finalDoc.Root.XPathSelectElement("/doc/members")
.Add(xdocAdditional.Root.XPathSelectElement("/doc/members").Elements());
}
}
}
// Supply the navigator that rest of the XmlDocumentationProvider code looks for
_documentNavigator = finalDoc.CreateNavigator();
}
I register the new provider from HelpPageConfig.cs:
config.SetDocumentationProvider(new MultiXmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/")));
Creating a new class and leaving the original one unchanged may be more convenient when upgrading etc...
Rather than create a separate class along the lines of XmlMultiDocumentationProvider, I just added a constructor to the existing XmlDocumentationProvider. Instead of taking a folder name, this takes a list of strings so you can still specify exactly which files you want to include (if there are other xml files in the directory that the Documentation XML are in, it might get hairy). Here's my new constructor:
public XmlDocumentationProvider(IEnumerable<string> documentPaths)
{
if (documentPaths.IsNullOrEmpty())
{
throw new ArgumentNullException(nameof(documentPaths));
}
XDocument fullDocument = null;
foreach (var documentPath in documentPaths)
{
if (documentPath == null)
{
throw new ArgumentNullException(nameof(documentPath));
}
if (fullDocument == null)
{
using (var stream = File.OpenRead(documentPath))
{
fullDocument = XDocument.Load(stream);
}
}
else
{
using (var stream = File.OpenRead(documentPath))
{
var additionalDocument = XDocument.Load(stream);
fullDocument?.Root?.XPathSelectElement("/doc/members").Add(additionalDocument?.Root?.XPathSelectElement("/doc/members").Elements());
}
}
}
_documentNavigator = fullDocument?.CreateNavigator();
}
The HelpPageConfig.cs looks like this. (Yes, it can be fewer lines, but I don't have a line limit so I like splitting it up.)
var xmlPaths = new[]
{
HttpContext.Current.Server.MapPath("~/bin/Path.To.FirstNamespace.XML"),
HttpContext.Current.Server.MapPath("~/bin/Path.To.OtherNamespace.XML")
};
var documentationProvider = new XmlDocumentationProvider(xmlPaths);
config.SetDocumentationProvider(documentationProvider);
I agree with gurra777 that creating a new class is a safer upgrade path. I started with that solution but it involves a fair amount of copy/pasta, which could easily get out of date after a few package updates.
Instead, I am keeping a collection of XmlDocumentationProvider children. For each of the implementation methods, I'm calling into the children to grab the first non-empty result.
public class MultiXmlDocumentationProvider : IDocumentationProvider, IModelDocumentationProvider
{
private IList<XmlDocumentationProvider> _documentationProviders;
public MultiXmlDocumentationProvider(string xmlDocFilesPath)
{
_documentationProviders = new List<XmlDocumentationProvider>();
foreach (string file in Directory.GetFiles(xmlDocFilesPath, "*.xml"))
{
_documentationProviders.Add(new XmlDocumentationProvider(file));
}
}
public string GetDocumentation(System.Reflection.MemberInfo member)
{
return _documentationProviders
.Select(x => x.GetDocumentation(member))
.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x));
}
//and so on...
The HelpPageConfig registration is the same as in gurra777's answer,
config.SetDocumentationProvider(new MultiXmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/")));
This question is specifically related creating a tree using multithreading and recursion.
I have got the code running that will create the tree using recursion but the time required to create that tree is more than I want to spend.
The reason for the slowness of that is because I am calling TaxonomyManager in Ektron CMS which takes a little bit to return and all the calls add up quickly. I was wondering if there is a way to create a tree using multithreading.
(I don't have the code at present with me but I will add that code as soon as I get access to that code).
If I go this route what the chances of me corrupting the tree as the tree is one root node and multithreading is going to add those nodes to that node at some point.
Thanks for any input anyone may have.
Edit: Added code. TaxonomyNodes is my class doesn't have a lot of properties. Has Id,Name,Description, Path (Stores the path in similar way as Ektron), HasChildren flag, ParentId, and public List Children.
public List<TaxonomyNodes> CreateTree()
{
try
{
TaxonomyManager tManager = new TaxonomyManager();
TaxonomyCriteria criteria = new TaxonomyCriteria();
criteria.AddFilter(TaxonomyProperty.ParentId, CriteriaFilterOperator.EqualTo, 0);
criteria.OrderByDirection = EkEnumeration.OrderByDirection.Ascending;
criteria.OrderByField = TaxonomyProperty.Id;
List<TaxonomyData> tDataList = tManager.GetList(criteria);
int index = 0;
if (tDataList != null)
{
foreach (TaxonomyData item in tDataList)
{
if (item.Name != "Companies" && item.Name != "Content Information Centers")
root.Insert(index++, new TaxonomyNodes() { ParentId = 0, TaxonomyId = item.Id, TaxonomyDescription = item.Description, TaxonomyName = item.Name, TaxonomyPath = item.Path, HasChildren = item.HasChildren, Children = new List<TaxonomyNodes>() });
}
}
index = 0;
foreach (TaxonomyNodes itemT in root)
{
itemT.Children = CreateNodes(itemT.TaxonomyId, itemT);
}
return root;
}
catch (Exception)
{
throw;
}
}
private List<TaxonomyNodes> CreateNodes(long taxonomyId, TaxonomyNodes itemToAddTo)
{
try
{
TaxonomyManager tManager = new TaxonomyManager();
TaxonomyCriteria criteria = new TaxonomyCriteria();
criteria.AddFilter(TaxonomyProperty.ParentId, CriteriaFilterOperator.EqualTo, taxonomyId);
criteria.OrderByDirection = EkEnumeration.OrderByDirection.Ascending;
criteria.OrderByField = TaxonomyProperty.Id;
List<TaxonomyData> tDataList = tManager.GetList(criteria);
List<TaxonomyNodes> node = new List<TaxonomyNodes>();
if (tDataList != null)
{
foreach (TaxonomyData item in tDataList)
{
node.Add(new TaxonomyNodes() { ParentId = taxonomyId, Children = null, TaxonomyId = item.Id, TaxonomyDescription = item.Description, TaxonomyName = item.Name, TaxonomyPath = item.Path, HasChildren = item.HasChildren });
itemToAddTo.Children = node;
if (item.HasChildren)
{
CreateNodes(item.Id, node[node.Count - 1]);
}
else
{
return node;
}
}
}
return node;
}
catch (Exception)
{
throw;
}
}
Rather than get into multithreading, which, though it may work, is not officially supported by Ektron's APIs and may present other challenges, I would recommend some form of caching or other storage for the data that does not require recursive DB calls.
Options:
1 - Ektron's Taxonomy APIs do include a GetTree method, which can pull the entire tree, up to a specified number of levels, and child items in a single API call rather than recursively. This may perform better and would be easily cached.
2 - Ektron provides API-level caching that can be readily enabled in the web.config by changing
<framework defaultContainer="Default" childContainer="BusinessObjects" />
To:
<framework defaultContainer="Cache" childContainer="BusinessObjects" />
3 - Use an eSync Strategy which will output the data you need (better to use your own streamlined objects than to store Ektron's with all the extra data) to something like an XML file. See this sample, http://developer.ektron.com/Templates/CodeLibraryDetail.aspx?id=1989&blogid=116, which I wrote to do this very thing. It hooks into the DB sync complete event and triggers a console application which writes the entire Taxonomy structure out to an XML file.
Word 2007 saves its documents in .docx format which is really a zip file with a bunch of stuff in it including an xml file with the document.
I want to be able to take a .docx file and drop it into a folder in my asp.net web app and have the code open the .docx file and render the (xml part of the) document as a web page.
I've been searching the web for more information on this but so far haven't found much. My questions are:
Would you (a) use XSLT to transform the XML to HTML, or (b) use xml manipulation libraries in .net (such as XDocument and XElement in 3.5) to convert to HTML or (c) other?
Do you know of any open source libraries/projects that have done this that I could use as a starting point?
Thanks!
Try this post? I don't know but might be what you are looking for.
I wrote mammoth.js, which is a JavaScript library that converts docx files to HTML. If you want to do the rendering server-side in .NET, there is also a .NET version of Mammoth available on NuGet.
Mammoth tries to produce clean HTML by looking at semantic information -- for instance, mapping paragraph styles in Word (such as Heading 1) to appropriate tags and style in HTML/CSS (such as <h1>). If you want something that produces an exact visual copy, then Mammoth probably isn't for you. If you have something that's already well-structured and want to convert that to tidy HTML, Mammoth might do the trick.
Word 2007 has an API that you can use to convert to HTML. Here's a post that talks about it http://msdn.microsoft.com/en-us/magazine/cc163526.aspx. You can find documentation around the API, but I remember that there is a convert to HTML function in the API.
This code will helps to convert .docx file to text
function read_file_docx($filename){
$striped_content = '';
$content = '';
if(!$filename || !file_exists($filename)) { echo "sucess";}else{ echo "not sucess";}
$zip = zip_open($filename);
if (!$zip || is_numeric($zip)) return false;
while ($zip_entry = zip_read($zip)) {
if (zip_entry_open($zip, $zip_entry) == FALSE) continue;
if (zip_entry_name($zip_entry) != "word/document.xml") continue;
$content .= zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
zip_entry_close($zip_entry);
}// end while
zip_close($zip);
//echo $content;
//echo "<hr>";
//file_put_contents('1.xml', $content);
$content = str_replace('</w:r></w:p></w:tc><w:tc>', " ", $content);
$content = str_replace('</w:r></w:p>', "\r\n", $content);
//header("Content-Type: plain/text");
$striped_content = strip_tags($content);
$striped_content = preg_replace("/[^a-zA-Z0-9\s\,\.\-\n\r\t#\/\_\(\)]/","",$striped_content);
echo nl2br($striped_content);
}
I'm using Interop. It is somewhat problamatic but works fine in most of the case.
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Word;
This one returns the list of html converted documents' path
public List<string> GetHelpDocuments()
{
List<string> lstHtmlDocuments = new List<string>();
foreach (string _sourceFilePath in Directory.GetFiles(""))
{
string[] validextentions = { ".doc", ".docx" };
if (validextentions.Contains(System.IO.Path.GetExtension(_sourceFilePath)))
{
sourceFilePath = _sourceFilePath;
destinationFilePath = _sourceFilePath.Replace(System.IO.Path.GetExtension(_sourceFilePath), ".html");
if (System.IO.File.Exists(sourceFilePath))
{
//checking if the HTML format of the file already exists. if it does then is it the latest one?
if (System.IO.File.Exists(destinationFilePath))
{
if (System.IO.File.GetCreationTime(destinationFilePath) != System.IO.File.GetCreationTime(sourceFilePath))
{
System.IO.File.Delete(destinationFilePath);
ConvertToHTML();
}
}
else
{
ConvertToHTML();
}
lstHtmlDocuments.Add(destinationFilePath);
}
}
}
return lstHtmlDocuments;
}
And this one to convert doc to html.
private void ConvertToHtml()
{
IsError = false;
if (System.IO.File.Exists(sourceFilePath))
{
Microsoft.Office.Interop.Word.Application docApp = null;
string strExtension = System.IO.Path.GetExtension(sourceFilePath);
try
{
docApp = new Microsoft.Office.Interop.Word.Application();
docApp.Visible = true;
docApp.DisplayAlerts = WdAlertLevel.wdAlertsNone;
object fileFormat = WdSaveFormat.wdFormatHTML;
docApp.Application.Visible = true;
var doc = docApp.Documents.Open(sourceFilePath);
doc.SaveAs2(destinationFilePath, fileFormat);
}
catch
{
IsError = true;
}
finally
{
try
{
docApp.Quit(SaveChanges: false);
}
catch { }
finally
{
Process[] wProcess = Process.GetProcessesByName("WINWORD");
foreach (Process p in wProcess)
{
p.Kill();
}
}
Marshal.ReleaseComObject(docApp);
docApp = null;
GC.Collect();
}
}
}
The killing of the word is not fun, but can't let it hanging there and block others, right?
In the web/html i render html to a iframe.
There is a dropdown which contains the list of help documents. Value is the path to the html version of it and text is name of the document.
private void BindHelpContents()
{
List<string> lstHelpDocuments = new List<string>();
HelpDocuments hDoc = new HelpDocuments(Server.MapPath("~/HelpDocx/docx/"));
lstHelpDocuments = hDoc.GetHelpDocuments();
int index = 1;
ddlHelpDocuments.Items.Insert(0, new ListItem { Value = "0", Text = "---Select Document---", Selected = true });
foreach (string strHelpDocument in lstHelpDocuments)
{
ddlHelpDocuments.Items.Insert(index, new ListItem { Value = strHelpDocument, Text = strHelpDocument.Split('\\')[strHelpDocument.Split('\\').Length - 1].Replace(".html", "") });
index++;
}
FetchDocuments();
}
on selected index changed, it is renedred to frame
protected void RenderHelpContents(object sender, EventArgs e)
{
try
{
if (ddlHelpDocuments.SelectedValue == "0") return;
string strHtml = ddlHelpDocuments.SelectedValue;
string newaspxpage = strHtml.Replace(Server.MapPath("~/"), "~/");
string pageVirtualPath = VirtualPathUtility.ToAbsolute(newaspxpage);//
documentholder.Attributes["src"] = pageVirtualPath;
}
catch
{
lblGError.Text = "Selected document doesn't exist, please refresh the page and try again. If that doesn't help, please contact Support";
}
}