What’s a ‘translatable label’?
A translation label is typically a short descriptive piece of text that is used in multiple places within a website (often every single page), for example ‘Print’, ‘Back’ and ‘Send to friend’. In the image below I’ve highlighted (in red) some text labels found in the header of an example website.
If you’re using SDL Tridion to create multi-language websites, these labels need to be available to content editors to add their own translations.
How to store translatable labels within SDL Tridion.
Perhaps it’s best to start by saying how not to store these items, as i’ve seen the following used in a few implementations:
- Hardcoded within templates – If the labels are entered directly into the template this means the template requires some localization and modification, this is bad for 2 very important reasons:
- The template is localized, so any changes made to the parent have to be manually integrated into the child
- It’s impossible for non technical users to actually edit these files.
- Within standard content schemas – The required labels are added (and often duplicated) within the content schemas, this means that each time a user needs to translate a lable (e.g. ‘Read more’) this must be performed in every instance.
Translatable label schema
OK, so a better solution to this is to create a new schema, that will contain all the labels you wish to translate:
I’ve named the schema ‘Translatable labels’ and added the following 4 fields:
- home
- search
- copyright_notice
Each field is a single text field that is mandatory. In your schema you can add all the labels your website needs and if you need any in the future, simply add a new schema entry.
Creating a master labels component
In order to create a master component, simply create a new schema in the parent content publication, this ensures our child local websites are able to ‘see’ therefore localize it.
Sidenote: I like to create a ‘Global components’ folder, where I typically store the components which website content that is used globally, examples would be the company address, website footer text etc.
How to reference the Translatable labels component
Before we dive into the code, we need to consider how our code will reference our translation labels component, if we use the TCM id hard coded the following will happen:
- If the component is deleted and recreated, the TCM id is lost
- If we move this code to another environment the TCM id will not be the same
- When we use this code in our local publication, the TCM is not the same
So in this example, I’ve created a new Metadata schema, that contains a component link field, which allows me to reference the translation label component, as I plan to associate this schema to the publication I’ve name the schema ‘Publication Metadata‘
Another sidenote: (I know another!) Whilst I think storing this item in the publication metadata is a good solution, be careful about throwing everything in a publication metadata schema as it can quickly become huge.  A neater solution is to seperate out the different meta types into their own components for example ‘SEO details’, ‘Site components’, ‘Region and language settings’ and embed those into a ‘Master’ publication metadata schema.
Anyway, now that the schema is created, associate to the publication metadata and then link the translation label to it.
The code
The code part is broken into two areas:
- A C# Template Building Block to get the component from the metadata and put it in the package.
- Dreamweaver template (DWT) code to display the translation lable within your layout.
C# Template Building Block code :
Create a new TBB in your .net project and use the following code to reference and put the translation component into the template builder package.
<pre>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tridion.Extensions.ContentManager.Templating;
using Tridion.ContentManager.Templating;
using Tridion.ContentManager.ContentManagement;
using Tridion.ContentManager.CommunicationManagement;
using Tridion.ContentManager.ContentManagement.Fields;
namespace Tridion.Templates.Library.Common
{
class AddTranslationLabelComponent : TemplateBase
{
public override void Transform(Engine engine, Package package)
{
this.Initialize(engine, package);
// get the publication object
Publication publication = this.GetPublication() as Publication;
ItemFields metaFields = new ItemFields(publication.Metadata, publication.MetadataSchema);
// 'translation_labels' below is the schema field name
ComponentLinkField complinkField = (ComponentLinkField)metaFields["translation_labels"];
// Put the translate lables component into the package
package.PushItem(complinkField.Name, package.CreateTridionItem(ContentType.Component, complinkField.Value));
}
}
}
</pre>
Note: I’m using the Tridion base project in this example, and of course i’m not doing any testing to see if the publication has any metadata, if the translation_labels field exists or if it contains a referenced component. In production code, I would always test for these things.
Dreamweaver DWT
As the component is in the package, all we need to do is make a reference to the component and field name as it appears in the package
@@translation_labels.home@@
Testing everything
In order to check everything works add the C# TBB and the DWT to a page or component template and run it.
I’ve highlighted with red boxes the following in the Template builder:
- AddTRanslationLabelComponent – The TBB containing the C#
- The translation_labels component added to the package
- ‘Maison’ – A localization of the word home (I know it should probably read ‘Accueil’ :))
Nice work (and gives me some ideas for a future blog post)! After everything’s set up, do you place the translation labels in the final markup in the modular template or from the presentation server side?
Oh, and one caution for after-the-fact schema changes for other readers: we can add new schema fields (as mentioned), rearrange the order of the fields, and update descriptions. However, any xml name changes will wipe content the next time they validate, typically when next opened.
Hi John,
Great post. We use the Publication Metadata to store Site Labels too but slightly differently. We have repeatable key/value pairs in the labels schema instead of a static schema and use a TBB to parse the templates to find any matches on the keys and replace it with the value. They can be referenced by using something like %%search-label%%. This also means that as well as referencing labels in our templating code, content editors can also reference these labels in text fields in their components and the default finish actions will parse and replace it for them.
Keep up the posts.
Ryan
Hi Ryan,
Thanks. Yes I’ve also implemented something similar, in this case putting exchange rates into content. There are tonnes of ways my solution here can be made better, what this really explains is the paradigm of using a separate component to store content that can be pulled into templates.
What I don’t like about offering a repeatable ‘key / value’ type schema is that you have to be aware that a user can modify the key as well as the value. I’m sure I heard a rumour that security at the field level is coming to SDL Tridion schemas, that would really help in situations like this.
Thanks for the comment
Hi Alvin.
In this example, the label is just rendered as HTML in the modular template, great thought perhaps something I should have mentioned that in the example I’ve provided, if changes are made to the labels, all the pages that use the template / label combination would need to be republished. As I said above, it was really just an introduction to the whole ‘using an external’ component.
Oh yeah… I’m not proposing changing any existing schema xml names, I’m just noting that new fields can be added!
Thanks for commenting, will I see you in Portugal next month?
I have 4 schemas as below
* Course_Ash (Schema type – Schema)
Fields: Name (Text), Description (Text), Image (MultiLink), Vegetarian (Text)
* DailyMenu_Ash (Schema type – Embeddable Schema)
Fields: Starter (Comp Link), Main (Comp Link), Dessert (Comp Link)
* WeeklyMenu_Ash (Schema type – Schema)
Fields: Week_number (Number), Monday (Emb Sch DailyMenu_Ash), Tuesday (Emb Sch DailyMenu_Ash), Wednesday (Emb Sch
DailyMenu_Ash), Thursday (Emb Sch DailyMenu_Ash), Friday (Emb Sch DailyMenu_Ash)
* Image_Ash (Schema type – Multimedia Schema)
Allowed multimedia types: gif, jpeg, png, bitmap
I have added a component using WeeklyMenu_Ash.
I am writing Component Layout DWT but am unable to access embedded components. My aim is to access the final component through embedded components, then component links and finally reaching the component.
Nice post John – Like you – I’ve had quite a bit of experience with translations are there are many different factors that will govern the overall solution.
I really like the idea of the key-value (embeddable, repeated) approach. With this you could also add, for example, field specific tool-tip text so it’s all translated in a single field
TranslateComponent
+Embeddable_key_value
+Key (e.g. search_label)
+Value (e..g SEARCH)
+ToolTip (e.g. Enter your text here)
Also to consider is whether to control text capitalisation through CSS/template code or, as I’ve had to do in some cases, through the addition of two separate ‘terms’ one with caps, one without – just to allow different locales to select how they display text (bear in mind in some languages you can’t just string.upper() as capitalisation changes the actual meaning of the letters too!!!)
Hi Ashim,
Sorry for not replying to this earlier. I suspect you have solved your issue now. For accessing embedded components you need to ensure they are placed into the package. SDL Tridion ships with the TBB files to do this, but they are not added to templates by default.
Personally I use the Dreamweaver get extensions built by Nuno Linhares (http://www.sdltridionworld.com/community/extension_overview/dreamweaver_get_extension.aspx) for this sort of thing, best of luck
Has it really been (only) two months?
John, here’s that follow-up post I promised (which you saw already).
Ashim, interestingly the “ash” in your examples match the initials of my last work place.
Ryan, thanks for sharing that label example. I know I’m not crazy (nor that creative) when I posted a request for similar functionality on http://ideas.sdltridion.com. I was calling them “place holders” but it’s the same idea as “merge fields” or “labels” and typically involves some kind of delimiter like “%%” or “{{ with “}}.”
More revelations on this — all of the above can work for localized content. With Ryan’s publication metadata or Mark’s key-value-and-more component approach if the keys, values, and other fields match–the template at the right level will have publication-specific content. For the “system component” approach John describes, simply localize at the right level.
Great post. For one client, we took our label component to another level of abstraction. We created a schema with a very simple repeatable key-value pair. The error in this way was that we had to provide the content of the key fields ( because we had to hard code the value key fields to our TBBs). So, we had LabelKey: FormTitle; LabelValue: Fill in the Form. The LabelValue is localized by content authors, while LabelKey is filled in just once, by the developer.
The flaw in this approach is that it creates a dependency on the developer, and a risk that the content author could change that LabelKey value ( we’d written our TBBs to look for an embedded k-v pair where the LabelKey matched a hard coded value that the developer had written). We liked that we could crank out translation label components on the fly, but we also had to acknowledge an expectation that we could have strong governance on the LabelKey field.
From the label component, we’d then put a component link field in whatever content schema we were using.
Excellent post John and very well articulated and structured as well