M# Tutorials

Learn to build .NET applications with M#. Our step-by-step tutorials will get you up-to-speed rapidly.
If you already know ASP.NET and C#, you can master M# in a week or two.

Tips & Tricks

In this lesson we will learn some useful tips and tricks that you could use in your applications.

Reduce number of phrases

It can be costly (both financial and performance) to translate and maintain a very long list of phrases in many languages, so when you start developing your application you have to keep this in mind.
For example in the admin section you can have several buttons with the names "Add Employee", "Edit Employee", "Delete Employee", "Open Employee", "Add Company", etc... To reduce the number of phrases you could rename those buttons to "Add", "Edit", "Delete", "Open", especially if you have a lot of CRUD pages.

Disable dropdowns auto translation

You will have to translate the majority of your dropdowns that's why when you create a form and there is a dropdown M# will by default translate all its values. This is a very useful behaviour, but in some cases you cannot translate the items because it is a list of users or companies. Fortunately you can easily bypass the translation and the creation of records in the translation dictionary, just set the "Text formula" attribute of your dropdown list to


in your form.

Use Unicode

Do not forget that some languages have accents or are even not using our alphabet. From the beginning of each application you have to keep this in mind, especially when you create websites which can be used all around the world and you may have to translate it to another culture later on. If you don't use or don't know what Unicode is please have a look at this article: The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets In the majority of your applications UTF-8 should be sufficient.

Write code carefully

If your text doesn't have a quote in your default language that doesn't mean the translation into another language won't have a quote. To avoid runtime problems pass your parameters in ASP and JavaScript by using the double quote and make sure to take this into account when passing translations to methods or modules.

Think to other languages

Language exceptions

As discussed earlier you have to think multi-lingual from the beginning of the development. Some languages have particularities and it's good to know some of them to facilitate the translation work and have a better result. Check at the following lists displayed in both English and French.

The word "Delete..." is a link for marking the employee as deleted. In English that corresponds to the action and not the verb. If we want to translate this into French the translation will be "Supprimer" corresponding to the verb. If now we display this as the status ("Deleted" in English") the French translation will be "Supprimé", this time with another variant, which is the genre. If the employee is a woman the word will finish with an extra "e", that's why the header of the employee column is "Employé(e)". Of course you cannot know all the rules for all languages but you can find good practises adapted to your needs for avoiding future problems.

Use of M# extensions

M# provides some extensions for strings, such as:

The first expression is a regular plural in English, but if you use a Chinese word the result will be the Chinese singular word followed by an "s", which is completely wrong.

Like in English and in the second expression, other languages also have some specific rules for plural words. If you want to correctly display a text using extension methods for pluralizing for example, you will have to write your own method for each of your languages (not necessary for English) or also add plurals in phrase translations and do something like:

You have more code to write because you need to check if the word is singular or plural and that will add more records to phrase translations in the database, but that will fix the problem with plurals.

Determine origins of a phrase

Sometimes you want to translate a word but it could have a different meaning depending on the context.
One solution to this could be to use another word more adapted to the context (i.e. change "Edit" to "Edit record").
Another solution is to keep trace of the origins of each phrase, in other word on which pages this phrase is used.

To do this create the PhraseTranslationURL Entity and add the two following methods in PhraseTranslation.cs. Note that we convert all URLs to lower case to avoid casing problems.

Now open your Global.asax file and add the following code in the



This line will help you to call the following method for each translation downloaded.

Now we have to change the method


to store the URL of the page. In the

public static void UpdateTranslations(string phrase, Uri uri)

method we are already inserting the new phrase for all languages if missing. Add the following surrounded code which is run for all languages even if the phrase is already translated. This is important to check even if the phrase is already persisted because a phrase can be on many pages.

In the code above note that we are checking in web.config if URL storage is enabled, that could be useful for deactivating this feature to improve performance once the application is online and all phrases are already stored for all pages. If everything is translated we don't need this feature.
With this implementation we can now display to admin users on which page a phrase is displayed.

Add statuses to phrases

For administrators it is not easy to manage the translation dictionary for an existing projects. The dictionary is only populated when a user request a translation or get a specific message from the application, so at the beginning you won't get all the phrases. Also the content added by users (i.e. dropdown lists) can be translated, so each time they add data a new phrase will be created for each language in your application.
To facilitate the job of administrators you may want to add a status to all phrases in the system and allow them to filter the list. If they don't want to translate a phrase (for example it is only displayed on admin area) they can decide not to translate it and hide the phrase.

For all the phrases they translated/imported you can automatically set the status to "Approved", "Pending" is the default status when a phrase is created. In the code you have to edit the "UpdateTranslations" method and set the Status property.


M# provides a great feature working on all browsers, which is Button templates. With this features you can easily convert all your buttons to images without the need to take care of the browser compatibility (gradients, corners...). The drawback of this feature is that it is not a good solution for multi-lingual applications.
To disable this feature go to your project settings in M# and set the attribute "Button style" to "Button" or "Link". Set the text of your button to

Translate("Generate PDF")

and the text will be automatically translated for all languages without affecting the style of your button which is now using CSS styles.

Use valid ISO codes

It is important to set and use valid ISO codes for languages because this code will be used in the Google Translator API (Translation, language detection). Use ISO 639-1 codes which is a two-letter code, you can find the full list on Wikipedia.

Adapt your master-pages

Do not forget to specify in your master pages what the language of the content is. The "lang" attribute is very important because it assists search engines and browsers. If you plan to use some JavaScript libraries dealing with languages you may have to specify this attribute.

Set language-specific styles

For some languages you may want to change the default style. Edit your master-page to set a new css class for using languages.

In the following example we set a custom font-size for all labels, but only on Chinese pages.

Do not fully trust Google API

The Google Translate API is a powerful API widely used on the Web, but we shouldn't trust all the responses from the API.
It is not fully reliable, for example if you want to auto-detect the language of a word/phrase you could get the wrong language because some words are similar in different languages. If you want to make sure that the language is correct you can use the API and ask the user to confirm the result.
The problem is the same for translations, the user may want to add a description in many languages, if so Google won't be able to detect the language and correctly translate this into another language. If you want to display an auto-translated content to users you may also want to display a link showing the content in the original language.

Bypass the phrase translation dictionary

The dictionary is a great feature because you can manage all your translations in one place and manage the logic how you want.
This is not well adapted for some scenarios you can face in a lot of Web applications, like for content blocks, email templates or CMS pages. For those purposes you may want to add a new Language property for those entities and manage this independently of the phrase translation logic. Another advantage of this is that you can use language-specific parameters in emails or even display different pages and sitemap in the visitor area.
The following example shows you an example on how to manage email templates for multi-lingual applications.

List of all email templates with information about which language is not yet translated
All translations of a specific email template
Translation of an email with language-specific features: Subject, Body and BCC

In our example, if an email should be sent to a Chinese user and if the template is not translated into Chinese, we can specify in the logic to not to send the email, to send the email in the default application language, or even send the email translated with Google API.
For a CMS page we may want to use different meta values depending on the language and change the title of the browser.
As you can see, the dictionary is very useful for phrases like form labels, list headers... but in some scenarios you will have to implement new functionalities and allow the logic to be extended.