Background
Although DotNetNuke® offers some powerful localization features, out of the box it offers only so called static localization. Static means that only non-content parts (ie. user interface) of a DotNetNuke site can be localized. Recent versions of DotNetNuke (since version 3.1.1.) offer a language selector which will be visible when more than one language is installed in the portal. To some, the existence of a language selector might suggest some kind of automatic translation feature, however, this is not the case. A language selector does just that: select a language, or to be more precise, set the Culture and UICulture of the current thread of the asp.net process, ie. set the output culture of the page being served to the client. This means that dates and numbers will be localized automatically, and UI texts will be localized by the DNN localization methods.
For further reading on DotNetNuke localization check these sources:
How to localize page information?
Due to the way DotNetNuke stores information about Pages/Tabs without culture information, we have no other option than to use our own storage for localized page information. The pagelocalization module uses a table where it stores localized data, in the current version the pagename, pagetitle, description and keywords are stored. Storing data is just half of the solution, we must of course also have a means to display the localized infomation. In order to do this, there are 2 options. One is to use a modification of the DotNetNuke core application, which will take care of all localizations. The other option is by using something like a SkinObject to do the localization. My personal preference is to never use a core modification, as it might always interfere with other modules (ie, change the expected behavior of the application). The module PageLocalization uses skinobjects to display all localized page information (like title, description, but also navigation).
Skin objects part of PageLocalization
The following skin objects are installed during installation of the PageLocalization module:
- MLBREADCRUMB - replaces core BREADCRUMB skin object
- MLLINKS - replaces core LINKS skin object
- MLMENU - replaces core MENU / SOLPARTMENU skinobject
- MLPAGETITLE - replaces core PAGETITLE skinobject
- MLTREEVIEW - replaces core TREEVIEW skinobject
In order to maintain compatibility as long as possible, the MLMENU and MLTREEVIEW skin objects do not make use of the menu provider as introduced in DNN 3.2, so they can be used in all DNN 3.x and 4.x versions. See the module help or online help for more information about the extra attributes of these skin objects.
Put PageLocalization to work in your portal
After you install the module, and put in on a page, you will see something very similar like this:

At the top of the module you can select for which language you are editing, and you can select the parent menu. To enable fast editing, you can edit all child menu's under one parent menu. The items in the parent menu drop down list will show all menu items that have children. Upon selection of another parent page, all child pages will show in the module below. All changes of the previous view will be saved automatically (you will see a message "The changes were updated successfully").
Apart from editing localized values you can also decide whether you want to make a page invisible for a given language. If you set a page to "Invisible", it will no longer show up in supported navigational controls. Mind you, if a page was already set to invisible in the page settings, you can not force it to show up with this module.
Of course you will want to make your localizations visible in your portal. Due to the way the localization of pages work, special skin objects are needed to do the work. In the downloadpackage of PageLocalization i included a sample skin (also available as free download from the downloadpage on this site, in the folder "ML Modules"). After you installed this skin, the available skins will look like this:

The skin variants are named after the support for the different Apollo Modules. This is the meaning of the letter combinations in the skins:
-
LS: Language Selector (support for Apollo MLLanguage Selector)
-
PL: PageLocalization (support for Apollo PageLocalization)
-
HM: Horizontal menu bar
-
VM: Vertical Menu (treeview)
-
Fixed: Fixed Width (770px)
-
Full: Full Width (100%)
Let's look at one of the variants, PL-HM-Fixed. This variant supports PageLocalization and has a horizontal menu and fixed width. If you look at the .html file you will see that the following tokens for ML skinobjects are used: MLPAGETITLE, MLMENU, and MLBREADCRUMB. Because MLPAGETITLE is not used in file "skin.xml", it will be parsed by the skinparser in its default form, so it will render invisible. As you can see, we use the ML skin objects exactly the same as the core skinobjects, however, ofcourse the token name is different.
Mind you, if you did not install Pagelocalization, or MLLanguageSelector, you will see tokennnames in the parsed skin instead of the actual skinobjects. This is default behaviour of the DotNetNuke skinparser, if you install the modules afterwards, you hae to reparse the skin.
If you are used to make / edit your skins in ascx mode, and never use the html/xml path, of course you can use the ML skin objects in exactly the same way as you are used to be using the core skin objects. If you take a look atone of the parsed skin files in the skin folder of your portal (in portals/_default/skins or portals/[portalID]/skins, depending on whether you installed the skin as host or as admin), for instance PL-HM-Fixed.ascx, you will see these ML skin objects specific registrations:
<%@ Register TagPrefix="dnn" TagName="MLPAGETITLE" Src="http://www.apollo-software.nl/Portals/0/~/DesktopModules/PageLocalization/MLPageTitle.ascx" %><%@ Register TagPrefix="dnn" TagName="MLPAGETITLE" Src="http://www.apollo-software.nl/Portals/0/~/DesktopModules/PageLocalization/MLPageTitle.ascx" %>
<%@ Register TagPrefix="dnn" TagName="MLPAGETITLE" Src="~/DesktopModules/PageLocalization/MLPageTitle.ascx" %>
<%@ Register TagPrefix="dnn" TagName="MLMENU" Src="~/DesktopModules/PageLocalization/MLMenu.ascx" %>
<%@ Register TagPrefix="dnn" TagName="MLBREADCRUMB" Src="~/DesktopModules/PageLocalization/MLBreadCrumb.ascx" %><%@ Register TagPrefix="dnn" TagName="MLMENU" Src="http://www.apollo-software.nl/Portals/0/~/DesktopModules/PageLocalization/MLMenu.ascx" %>
Of course, the registration of the skin object (user control) has to point to the actual source of the control, in this case the controls exist in the PageLocalization module folder.
Next, the usage of the skin object in the page is quite simple:
<dnn:MLPAGETITLE runat="server" id="dnnMLPAGETITLE" />