There are various ways to create a data-driven multi-language site, but the method I will show in this article series uses an underused technique involving ColdFusion custom tags. Basically, the technique shown will turn any simple, well-formed HTML or XHTML page into a content management system with only one tag required on the page.

This first part will show the principles behind the custom tag technique. The next part will show how to implement the multi-language aspect. The third part will create an administrative interface to administer the system. There are articles on the web demonstrating various uses of CF custom tags, so I'll assume you have at least a basic knowledge of them. If you are unfamiliar, read the introductory article Breathing New Life into Custom Tags by Neil Giarratana:
http://www.communitymx.com/abstract.cfm?cid=9D776

Some articles that I wrote that discuss custom tags at CMX that you may find useful include:

Creating a ColdFusion Custom Tag for US States
http://www.communitymx.com/abstract.cfm?cid=E50C2

Using ColdFusion Custom Tags as a Site Template parts 1, 2, and 3:
http://www.communitymx.com/abstract.cfm?cid=D7B46
http://www.communitymx.com/abstract.cfm?cid=7A162
http://www.communitymx.com/abstract.cfm?cid=D0172

Custom Tags

ColdFusion custom tags have been around a while, but the <cfimport> tag was introduced in CFMX 6. Beginning with CFMX, tag libraries can be imported to your page using a simple line:

<cfimport taglib="yourfolder" prefix="mytag">

Now, any files saved within /yourfolder become custom tags for use on a page importing the library. For example, a simple breadcrumbs custom tag saved as breadcrumbs.cfm in /yourfolder can be called like this on the page:

<mytag:breadcrumbs />

This is much simpler than the old method of calling ColdFusion custom tags with <cfmodule> or using <cf_tagname> syntax. For one, it is easier for your designers to insert simple tags like this into a CFM page.

It can become even easier by using custom tags without the prefix. First, import the tag library at the top of a page:

<cfimport taglib="yourfolder">

Now, the tag would look like this:

<breadcrumbs />

By not using a prefix, you run the risk of colliding with actual tags on your ColdFusion page, such as basic HTML tags.

<p>This is not a custom tag</p>

The standard <p> tag is a part of HTML, but what if you save a file named p.cfm in the custom tags directory? The simple answer is that all <p> tags on your page have now become ColdFusion custom tags. Now that the <p> tag is a custom tag, you can do whatever you want with it, including outputting the content of the tag, changing the attributes, saving things to a database, reading files, etc. In short, the common <p> tag (or any other HTML tag for that matter) can now be used with the full arsenal of the ColdFusion language.

Try it

For a simple tryout, create a blank page at the root of a ColdFusion site called "testtags.cfm" and include this code:

<cfimport taglib="html">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Test Tag</title>
</head>

<body>
<p>This tag has nothing interesting in it.</p>
</body>
</html>

Next, create a folder in the root of that site called "html". In that folder, save a completely blank page named p.cfm. On that page, insert the following code:

<cfparam name="thistag.executionmode" default="">

<cfswitch expression="#ThisTag.ExecutionMode#">
<cfcase value="start">
<p>
</cfcase>

<cfcase value="end">
<br/><br/>Nothing interesting indeed.</p>
</cfcase>
</cfswitch>

The basic ColdFusion custom tag used the built-in construct ThisTag, and it's property ExecutionMode to differentiate between the start and end tag. In the end tag, we are appending some text. Now, when you browse the testtags.cfm page, you should see this:


Figure 1: Simple tag output

The content from the tag on your ColdFusion page was output, but the content from the custom tag was also output. Nothing too difficult so far. As you can see, the custom tag was used to append content. What if we want to remove the content completely and replace it with our own? We use another build-in property of ThisTag -- GeneratedContent. Change the tag to read like this:

<cfparam name="thistag.executionmode" default="">

<cfswitch expression="#ThisTag.ExecutionMode#">
<cfcase value="start">
<p>
</cfcase>

<cfcase value="end">
<cfset thisTag.generatedContent = "Sprechen sie deutsche?">
</p>
</cfcase>
</cfswitch>

Now, when you browse your page, the entire tag contents are replaced and you see this on the page:


Figure 2: Page content replaced by custom tag

So far so good, but does this mean you have to create separate tags for each HTML tag on your page? Yes, you will, but we'll take a modular approach. What we'll do is create a generic base tag used by each HTML tag we want to modify, then create separate files for each tag that we want to replace. Create a file called basetag.cfm in the /html directory and add the following content to it:

<cfparam name="thistag.executionmode" default="">
<cfparam name="tag" default="p">
<cfswitch expression="#ThisTag.ExecutionMode#">
<cfcase value="start">
<cfoutput><#tag#></cfoutput>
</cfcase>

<cfcase value="end">
<cfset thisTag.generatedContent = "Sprechen sie deutsche?">
<cfoutput></#tag#></cfoutput>
</cfcase>
</cfswitch>

This is identical to the p.cfm file that we previously created, only now we added a new parameter called "tag", and used the parameter in our output -- instead of <p> we are using <cfoutput><#tag#></cfoutput>. Next, create a file called p.cfm in the /html directory with the following code on it:

<cfset tag="p">
<cfinclude template="basetag.cfm">

If you browse your testtags.cfm page, you should see the same result now. We'll use the basetag.cfm file to create the functionality for the bulk of the HTML tags in our pages, and create files called h1.cfm, h2.cfm, h3.cfm, td.cfm, th.cfm, and span.cfm in our /html directory using the same content as p.cfm -- only changing the variable tag. For example, in the h1.cfm file:

<cfset tag="h1">
<cfinclude template="basetag.cfm">

And so on. These are the bulk of the content tags in our simple site. Now, any page that we have that contains this line at the top -- <cfimport taglib="html"> -- will have its <p>, <h1>, <h2>, <h3>, <td>, <th>, and <span> tags transformed into custom tags that will become the basis of our content management system.

Conclusion

In this first part, I've presented a very basic concept of using a ColdFusion custom tag to replace a built-in HTML tag. Using this technique I will create a simple multi-language content management system in the next part of the series.