Does the way we translate our website result in performance issues? - c#

Background
Our site is a press site and is viewed by many people around the globe. Obviously this means that we will be localising the site in as many languages as possible. A professional translator will be hired for each language.
How our site works currently
The way we have planned to do this is by storing a translation for each element of the page in the database linked by a Guid. So when the page loads the strings are pulled out of the database using the Guid and the language preferences of the user.
We have several documents in our project that contain english translations. Such as this:
public class StandardButtonToken : LocalisationToken
{
protected StandardButtonToken(string defaultText, Guid key) : base(defaultText, key)
{
}
public static readonly LocalisationToken Update = new StandardButtonToken("Update", Guid.Parse("8a999f5b-7ca1-466d-93ca-377321e6de00"));
public static readonly LocalisationToken Go = new StandardButtonToken("Go", Guid.Parse("7a013ecc-0772-4f87-9f1f-da6a878a3c99"));
public static readonly LocalisationToken Edit = new StandardButtonToken("Edit", Guid.Parse("c31be427-5016-475d-997a-96fa5ff8b51f"));
public static readonly LocalisationToken New = new StandardButtonToken("New", Guid.Parse("f72d365c-b18f-4f01-a6e4-b0cd930dc730"));
public static readonly LocalisationToken More = new StandardButtonToken("More", Guid.Parse("bd4da7df-afd2-481e-b6b6-b4a989324758"));
public static readonly LocalisationToken Delete = new StandardButtonToken("Delete", Guid.Parse("ab00ec14-4414-4cda-a8e2-4f03c9e7c5a8"));
public static readonly LocalisationToken Add = new StandardButtonToken("Add", Guid.Parse("01e44600-a556-4a07-8a2a-e69a1ea79629"));
public static readonly LocalisationToken Confirm = new StandardButtonToken("Confirm", Guid.Parse("4c50e91e-3e2f-42fa-97aa-9f1f6f077f09"));
public static readonly LocalisationToken Send = new StandardButtonToken("Send", Guid.Parse("24121766-f424-4d73-ac58-76f90d58b95c"));
public static readonly LocalisationToken Continue = new StandardButtonToken("Continue", Guid.Parse("dd2ca0e5-8a35-4128-b2e8-db68a64a6fe5"));
public static readonly LocalisationToken OK = new StandardButtonToken("OK", Guid.Parse("9a359f93-7c23-44ad-b863-e53c5eadce90"));
public static readonly LocalisationToken Accept = new StandardButtonToken("Accept", Guid.Parse("3206a76b-1cd7-4dc3-9fff-61dfb0992c75"));
public static readonly LocalisationToken Reject = new StandardButtonToken("Reject", Guid.Parse("f99c6a9c-6a55-4f55-ac4b-9581e56d18d3"));
public static readonly LocalisationToken RequestMoreInfo = new StandardButtonToken("Request more info", Guid.Parse("19f3d76b-dafa-47ae-8416-b7d61546b03d"));
public static readonly LocalisationToken Cancel = new StandardButtonToken("Cancel", Guid.Parse("75617287-5418-466b-9373-cc36f8298859"));
public static readonly LocalisationToken Publish = new StandardButtonToken("Publish", Guid.Parse("efd87fd4-e7f1-4071-9d26-a622320c366b"));
public static readonly LocalisationToken Remove = new StandardButtonToken("Remove", Guid.Parse("f7db5d81-5af8-42bf-990f-778df609948e"));
}
Everytime we create a page we make sure the buttons use these Tokens instead of manually writing the text. So if we decide we need a new button we will add a new token in the file below and when the site is run for the first time it will check if it exists in the database and if not it will be created.
So when it comes to the translating we will send these tokens off to the translators and they will change the text only. This will then be added into the site in the relevant language and the page will call the correct translation dependant on the language selected.
Problem/Question
Our translation tokens have the default text as strings, but I'm concerned that the server has to load all of these text strings into memory at start up. They're actually only ever used to store the translation in the db and never otherwise used in code, so I believe it might be a bit wasteful. Instead I believe we could call these translations separately when required, perhaps from some kind of look-up table that's not in-memory.
So the question is. Is the way we are currently doing this going to cause performance issues?
If so can anyone suggest any better solutions?
In total there are 1000's of these tokens in our site.
Google has not been very helpful to me on this occasion so any advice would be much appreciated. I have tried as hard as i can to word this so that it makes sense. Its not an easy one to explain.
Thanks in advance for any help people can provide.

I'm currently working with a team on a project in which we had a similar situation. Our project is a client/server based application. The database with our translations rests on the server and all our controls have default English values. Originally when any new window was opened we read the database and pulled any necessary translations down and translated the controls. This way only the values we needed translated where in memory and only as long as that window needed them. When the window was closed the memory would be reclaimed using garbage collection.
What we discovered was even with all the translations for every button, label, column header, etc... for the entire system was loaded into memory we where only dealing with a couple hundred K. In the end what we did was:
the user logs on:
if they default to another language besides English a data table is set up in memory and populated with the translations from all user controls in our system from the server.
This data table is given a primary key to help improve queries against it. As long as the app is open this data table exists.
Any time a user control is instantiated a method runs that looks up the translation and applies it.
The time it took to log in the user did increase but only by a few milliseconds on average.
Having said all this I wonder if you could use a similar design. This idea would keep the server from having to track translations per session. It would just feed the page to the user.
User logs in:
a datatable object is populated with all the translations for the site
WriteXML() is called
the resulting XML is sent to the client
When the user navigates to a new page:
a client side script is called that uses the XML to translate the page on the client machine.
You could add some caching so that the XML is only replaced when your site is updated or you could just have each user download the XML every time at log on. Either way it takes the load off of the server.

Ignoring other implementations and focusing on the setup you're using, the answer is "yes" and "no".
Yes, there can be performance issues with the method you're following if the number of incoming requests grows and especially as the number of tokens increases. This relationship can be easily explained as "the more requests that come in, the more work the server has to do. the more tokens that exist, the more work the server has to do. If both requests and tokens increase, you're exploding the amount of work the server has to do."
The "no" could be accomplished by adding on to your current solution. You can add a cache to your setup that will save translated pages so that the server would not need to query the database or translate each page per-request. For instance, if you have one page mypage.aspx that contains 20 translatable tokens - let the server translate it the first time and then save the translated file as, say, /localized/mypage.EN.html and all future requests (if the original page hasn't been modified or new tokens haven't been added) will just be sent the cached page instead of re-translating each time.
Additionally, you could have the server generate all translations when the page is updated or tokens are updated instead of waiting for a client-request to come in.

Related

Should a static class be used for caching data in a ASP.NET MVC application?

I have a set of the data that hardly ever changes, but which is required frequently from many actions in my ASP.NET MVC application.
It seems too costly to do a database roundtrip every time that data is required, so I decided to cache it in a static class that looks like this:
public static class MyCache
{
static DatabaseHelper databaseHelper = new DatabaseHelper();
static List<MyItem> myList = null;
public static List<MyItem> Get {
get
{
if (myList == null)
myList = databaseHelper.GetAll();
return myList;
}
}
}
Are there any issues in storing data like that? Are there better approaches to cache data?
When you say Cache then there are many things to consider.
How long data will stay in cache even after it is not consumed since long ?
What is the size of data ?
How you expire that data ? Are you sure that data you store in cache is not going to change once you load it ?
Now Static class as Cache ( More specially static fields). This is workable solution but you have to consider above points as well.
In your cache you have to consider that once you load in static field it is not going to load again till you restart application or set list as a null. Another advice is that list property only expose get as public and private for set so you have better control over it.

Multilanguage site performance

I'm currently working on a site (ASP MVC) that support Multilanguage where every web content is stored in Database, for example I have english version, spanish version, etc. But I'm worried about the performance when it goes to production because everytime a user hit my page, there are at least 20 database calls to get the content.
Is there anything I can do to make this more efficient?
What I can't do is :
Merge all database call into 1 call on every page load (this takes
too much effort).
Make a separate html page for every language (I need the end user to be able to add new language without me changing the code hence the
database design).
I was thinking about caching everything in user's browser and compare it everytime they hit my page and it will only call the database if it doesn't match but I'm not sure how to approach this.
Any help will be appreciated and sorry for bad english.
I would suggest to go with static dictionary in this case, as #Vsevolod-Goloviznin suggested in the comments.
Let me elaborate my approach
You probably have a localized resource in your database identified with some named key and language key as well:
var homePageTitle = Database.GetResource("homeTitle", "es");
You should build up a static dictionary that will be used as cache and will have all the resources in the database in memory, for easy and convenient access:
public static MultiLanguageManager {
private static Dictionary<string, Dictionary<string, string>> ContentCache;
...
public static GetResource(string key, string language) {
return (ContentCache[language])[key];
}
}
Then in your front-end you will have something like this:
...
<title>#MultiLanguageManager.GetResource("aboutTitle", "en")</title>
...
Whenever user changes the localized content in the database, you should rebuild the ContentCache dictionary manually:
// update localized content
...
MultiLanguageManager.RebuildContentCache();
...
By using this approach you can reduce the number of database calls to minimum (retrieve only logic units, and not static resources), and control the consistency of your localization data.
One possible drawback might be the size of the static dictionary that you will build, but with Today's abundance of resources, this should not be a problem in 99% of the cases.

Session vs static Property in c#

I wanted to use some data from one page to another. General solution is to use Session (most of recommends). My boss don't like sessions and he suggested me to do same work by using C# Property in common class as below
public static long parentId { get; set; }
and set it one one page as
Common.parentId = "any value";
and use it on other page like
string anyVariable = Common.parentId
and it worked. We get rid of session expiration as well. But why most of people recommend session. Is property another state management thing?
If you are going to store some data using simple static property you must understand that it will be shared among all your users. Sessions are not for this. But I don't see any reasons not to use sessions if you want to store user data somewhere.
In my project it is very convenient, especially when we use SQL-server to store sessions - we can update our website without any losing users' sessions data.
You can check all possible ways to hanle sessions for example here http://msdn.microsoft.com/en-us/library/75x4ha6s(v=vs.100).aspx

Dynamic localization of messages

I have made a simple localization of messages. All messages are stored in the static class Lng
public static partial class Lng
{
public static readonly string AppName = "My application";
public static class Category1
{
public static readonly string ConfirmDelete = "Are you sure want to delete?";
}
}
In code usage is as simple as referencing fields
MessageBox.Show(Lng.Category1.ConfirmDelete, ...
Then there is a manager, which does following:
language selection
load corresponding translation
updating fields via reflection
export currently selected language on application exit for an update (in case if default language is selected - to create first translation for any other language)
It's irrelevant of how language files looks likes, but here is a reflection part
TranslateLng("Lng.", typeof(Lng));
...
private static void TranslateLng(string parent, Type type)
{
foreach (Type nested in type.GetNestedTypes())
{
string child = string.Format("{0}{1}.", parent, nested.Name);
TranslateLng(child, nested);
foreach (var field in nested.GetFields())
{
string key = child + field.Name;
DefaultAdd(key, (string)field.GetValue(null)); // store value in default language dictionary (if not created yet)
field.SetValue(null, GetValue(key)); // get value for currently selected language
}
}
This system has one problem: all messages are defined in one class, which required manual management (deleting and updating messages when updating code which uses them).
And I was thinking to change manager to register strings dynamically and simplify usage to something like
MessageBox.Show(Lng.Text("Are you sure want to delete?"), ...
So that text is defined right where it used, duplicated text can be handled by manager and so on.
There are however 2 problems:
I will need a complete list of all messages at the end of application run to export complete list of messages (for currently selected language). What if some of Lng.Text() are never called at that run? Is there a way to register them as they are used in code (compile time?)? So that all calls will be registered somehow, even if peace of code is never used.
How to generate key. I could use CallerMemberName, but right key are more useful, as they are telling exact purpose. To example, Lng.Configuration.Appearance.CaptionText. I could call Lng.Text(key, message), but then I have to manage keys, ensure in their uniqueness, which doesn't appeals me.
I recently worked on a project with internationaliztion and we used Resources in con junction with the Sisulizer program with great success. Having the resources solves your key problem as you manually enter the key when you extract the resources. You also get great support from Resharper which makes the whole process a breeze.
Sisulizer is then used to extract resources as well as strings hard-coded in our Win Forms and WPF classes. It can export a CSV which you can give your translators and it also supports pseudo translation, which makes testing such apps very easy as well.

C# Application - storing of preferences in database or config file?

I have an application that uses SQLite, which is extremely light weight and quick. I have some preferences that don't necessarily need to be loaded on startup, but might need to be used at various times depending on where the user goes. That being said, I can't decide where to store this information.
Q1: Should I just go ahead and store it in the database? Should I store it in a config file?
Q2: Should I load and store the preferences and other data at startup even if they're not necessarily being used right away? Or should I just query the database when I need them?
Example: My application can store the company information for the company that is using the software. Company name, company phone, etc. The only time this information is used is when the software auto-prints a letter, or the user goes to edit their company information in the program.
EDIT: I've realized that this comes down to application settings vs user settings. My program does not have multiple users per copy of the software. That being said, I would suppose these would be application settings.
What you may want to do is write a class that encapsulates the settings and then reads them into Hashtable.
You could have a basic GetSetting method that looks up a setting based on a name. If the setting is located in the Hashtable, return the value, otherwise go to the DB to find the setting and then store it in the Hashtable. You can then write separate properties for each setting you want, each calling the GetSetting/SetSetting methods.
This allows you to store the settings in the DB easily, and caches the reads to avoid constantly reading the DB.
public class Settings {
private object SyncRoot = new object();
private System.Collections.Hashtable _cache = new System.Collections.Hashtable();
public T GetSetting<T>(string xPath, T defaultValue)
{
lock (SyncRoot)
{
if (!_cache.ContainsKey(xPath))
{
T val = GetSettingFromDB<T>(xPath, defaultValue);
_cache[xPath] = val;
return val;
}
return (T)_cache[xPath];
}
}
public T GetSettingFromDB<T>(string xPath, T defaultValue)
{
// Read from DB
}
public void SaveSetting<T>(string xPath, T value)
{
lock (SyncRoot)
{
if (_cache.ContainsKey(xPath))
_cache[xPath] = value;
}
SaveSettingToDB<T>(xPath, value);
}
public T SaveSettingToDB<T>(string xPath, T defaultValue)
{
// Read from DB
}
}
Then just create a class with a bunch of properties like this:
public static bool BooleanFeature
{
get { return Settings.GetSetting<bool>("BooleanFeature", true); }
set { Settings.SaveSetting<bool>("BooleanFeature", value); }
}
Now you can do this in your code:
if (Setting.BooleanFeature) {
// Run certain code
else {
// Run other code
}
How many settings are you looking to save? Using the built-in settings feature is pretty painless.
http://msdn.microsoft.com/en-us/library/aa730869.aspx
Storing configuration data in a file is good for light-weight settings that rarely change. Usually you'd do this for settings that are different between development and production and are used to get your application up and running.
After that, everything else is best stored in a database. This gives you the option for good user interfaces to modify the settings, load them when needed, save them during upgrades to your system, be available if you're using multiple front-ends (versus saving the configuration in a file and ensuring all front-ends have the same up-to-date files.)
In addition to JTAs answer I would like to add that I've used 3 methods and they all have their up and down sides.
Storing them in the built-in one
does actually lock them to the
running user. So for instance if
multiple users use your app, there
will be independent settings for
each user. If this is what you want,
pick this one.
Storing them in the database is
useful if you do not want it to be
bound to a user but rather to the
database. Though you cannot change
these settings from outside the app.
I've used a config-class that I
serialize with XML if I need to edit
it with an xml-editor. For instance
this is very useful if you are
running a service.

Categories