Click here to Skip to main content
15,885,141 members
Articles / Mobile Apps

An International Hangman Game for the Pocket PC

Rate me:
Please Sign up or sign in to vote.
4.03/5 (16 votes)
29 May 2004CPOL6 min read 80.4K   201   14   15
As globalization increases internationalized applications become more important. This hangman game is a fun introduction to some of the internationalization features of the .NET Compact Framework.

The hangman game on a Pocket PC configured for Catalan

The hangman game on a Pocket PC configured for Catalan

Introduction

This article is a basic introduction to the internationalisation (or should that be internationalization) features of the .NET Compact Framework. The .NET Compact Framework has, just like its bigger brother, extensive features that assist the developer to write applications for multiple regions. Much of this support is automatic, which makes development so much easier. However, there are some things that should be thought of in advance to help give your application international support.

For the purposes of demonstrating the features, I have based the code around a Hangman game which I hope you also find fun and entertaining in itself even if you are not interested in internationalization. The final game is available in English, French, Catalan and Spanish. Curiously, these are also the major languages spoken in Europe on the Prime Meridian.

Background

An internationalized application (also known as a globalized application) is one where the application is enabled to handle international data. The specific translations are known as "localizations".

Hangman Implementation

The Hangman game has a LocaleManager class which is used to manage the resources and means that the game can have the language altered while it is running. The static initialiser for the class sets the current culture to be the same as the current UI Culture so that at least the game will start in the same language as is set in the Regional Settings for the Pocket PC (assuming, of course, that the game has resources in that language).

C#
static LocaleManager() 
{
    _current = CultureInfo.CurrentUICulture;
    Assembly asm = Assembly.GetExecutingAssembly();
    _resMan = new ResourceManager("Hangman.hmlocal", asm);
}

During the game, any time a string is used that will be output to the user, then the text is retrieved from the correct set of resources by the LocalManager.GetString(string id) method:

C#
public static string GetString(string id) 
{ 
    return _resMan.GetString(id, _current); 
}

You can see that this is a very simple method that just retrieves the string with the given identifier (I'll come to them in a moment) and for the current culture, that was retrieved in the static intialiser. If a culture is specified that is not available then the framework will use the fallback culture as a backstop so that at least something is available. The following diagram illustrates the organization of the culture information in .NET (which is derived from RFC 1766[^]).

Culture Hierarchy

I'll come to how this is translated into the application in a moment. The green layer at the top of the hierarchy chart is the fallback. This is what will be used if the system cannot match any other culture. The second level, with the aqua blue background, is the primary language tag. This level doesn't define things like culture specific date formatting (think of the difference between British English and American English - 1/2/03 can be the first of February or the second of January, or between using commas [in Continental Europe] or full stops [in English speaking countries] for the decimal place marker in a number). Finally, the third level, with the yellow background, adds the first sub-tag which in effect adds the region coding. The region coding helps define things like the date and number formats.

Validating User Input

For the purpose of the game, the user is permitted to type in any letter, however the same letter can have several representations. Traditionally, in English speaking countries, this type of comparison is taught along the lines of setting the letter case to be the same then comparing. For example:

C#
if (myStringA.ToLower() == myStringB.ToLower()) {/*do something*/}

Certainly, this is what I was taught in university and I don't see much evidence of that changing.

In a more international context, for example, the letter "a" can be written in upper case "A", with an acute "á", a grave "à", a circumflex "â", a tilde "ã", a dieresis "ä" which is sometimes also called an umlaut, a ring above "å" and so on (we won't even go into macrons, breves, ogoneks and all manner of other modifications and their uppercase equivalents to such a simple letter).

It is possible to compare the letter "a" with all these variations, but myChar.ToLower() just won't be sufficient in this case. The characters need to be converted to a string, and the two strings can then be compared with the InvariantCulture. The LocaleManager class in the game implements this as:

C#
public static bool IsEqual(char a, char b)
{
    // The Compare method doesn't have char overloads so convert
    // the characters in to a string
    string sa = StringInfo.GetNextTextElement(new string(a,1));
    string sb = StringInfo.GetNextTextElement(new string(b,1));

    // Perform a culture neutral comparison
    int res = CultureInfo.InvariantCulture.CompareInfo.Compare(sa, sb,
        CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace);

    // If the comparison yielded a result of zero, then char a and b
    // are equal (disregarding case and accent)
    return res == 0;
}

Localized Resources

With Visual Studio, one of the easiest things to do is to create a resx file for each language (and region) that is supported. These translate into satellite assemblies when the solution is built. The resx file is simply an XML file that contains the localized strings. In the demonstration game, the fallback name of the resources files is "hmlocal", and to add extra cultures, all that needs to happen is an additional resx file created in the format fallback.language[-region].resx (the region element is optional).

Although the demonstration application doesn't show this, the resx files don't just have to contain strings, they can contain any arbitrary objects such as graphics, audio, or anything else that you can dream up.

For example (a subsection of hmlocal.resx):

XML
<data name="play_timed_intro">
    <value>You have {0} seconds to guess the word or phrase!</value>
</data>
<data name="play_intro">
    <value>You have to guess the word or phrase!</value>
</data>
<data name="play_hurry">
    <value>Hurry! You have {0} second left!</value>
</data>

and it's Catalan equivalent from hmlocal.ca.resx:

XML
<data name="play_timed_intro">
    <value>Tens {0} segons per endivinar la paraula o frase!</value>
</data>
<data name="play_intro">
    <value>Has d'endivinar la paraula o frase!</value>
</data>
<data name="play_hurry">
    <value>Vinga! Et queden nomes {0} segons!</value>
</data>

Satellite assembly structure

File structure of the Satellite Assemblies relative to the main assembly

When the project is built, Visual Studio places all the localized resources into satellite assemblies. The fallback resources go in the main assembly and culture dependent assemblies are created in an appropriate subfolder immediately below the main assembly.

Differences between the CF and the full .NET Framework

In the full .NET Framework, it is possible to set the CurrentCulture on a CurrentThread which, in turn, changes the default culture for your application. However, this is not available in the Compact .NET Framework. In normal circumstances, it would be highly unlikely that an application would want to do this and so therefore it is not supported.

Points of Interest

If you are interested in why the Options tab and the Game menu page reference to "Player 1" when there can be only one player is because at some point in the future, I intend to expand the game to allow a two player mode where players can communicate (via IR or Bluetooth) the words to each other.

References and Resources

If you want to learn more about localization and globalization then you may find the following link useful.

Thanks to

Thanks to my good friend, and fellow CPian, David Llamas[^] who did the Catalan translation and corrected my Spanish translation (apparently, I used old fashioned words that a grandmother would use). And also to Jeannette who is a friend of my mother's and did the French translation, despite never having used a computer before.

History

This is version 1.0.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
Scotland Scotland
Have been a Code Project MVP 5 years running and was Microsoft C# MVP 4 years running, MBCS, MIAP and a whole bunch of other stuff. Now I just help run Scottish Developers which is a user group with software development events in Edinburgh, Glasgow and Dundee and I have also started an open source project to help with Password Validation

Main topics I blog about:
* Parallelization in .NET
* Code Quality
* Data Security

Comments and Discussions

 
GeneralValue does not fall in the expected range Pin
Deepa DB14-May-10 2:36
Deepa DB14-May-10 2:36 
Generalquestion about locale setting Pin
PiX_2k310-Apr-07 0:28
PiX_2k310-Apr-07 0:28 
GeneralRedundant Code Pin
Garth Watkins15-Mar-07 2:49
Garth Watkins15-Mar-07 2:49 
GeneralRe: Redundant Code Pin
Colin Angus Mackay15-Mar-07 7:58
Colin Angus Mackay15-Mar-07 7:58 
GeneralPlatformNotSupportedException zh-chs Pin
Samuel8421-Jun-06 20:09
Samuel8421-Jun-06 20:09 
Hi can yo'll let me know what is this error.
I've developed an application which supports two languages english and chinese , i've used file names accordingly hmlocal.es.resx and hmlocal.zh-chs.resx, but when i set the culture to "zh-chs", i have get PlatformNotSupportedException. what could be the possible reason.

I have tried french with the file name hmlocal.fr.resx, it seems that european languages are recogonised what could possibly be the problem ?
GeneralRe: PlatformNotSupportedException zh-chs Pin
Colin Angus Mackay21-Jun-06 20:19
Colin Angus Mackay21-Jun-06 20:19 
GeneralRe: PlatformNotSupportedException zh-chs Pin
Reza Ghorbani25-Feb-07 23:48
Reza Ghorbani25-Feb-07 23:48 
QuestionHow do you create the Installer .MSI? Pin
benreilly18-Oct-05 14:31
benreilly18-Oct-05 14:31 
Generalplease help me Pin
sreejith ss nair18-Sep-05 21:16
sreejith ss nair18-Sep-05 21:16 
GeneralRe: please help me Pin
Colin Angus Mackay19-Sep-05 1:17
Colin Angus Mackay19-Sep-05 1:17 
GeneralRe: please help me Pin
sreejith ss nair20-Sep-05 19:33
sreejith ss nair20-Sep-05 19:33 
GeneralNice Colin! Pin
Megan Forbes8-Jun-04 9:49
Megan Forbes8-Jun-04 9:49 
GeneralRe: Nice Colin! Pin
Colin Angus Mackay8-Jun-04 10:06
Colin Angus Mackay8-Jun-04 10:06 
GeneralRe: Nice Colin! Pin
Aaron Eldreth8-Jun-04 10:20
Aaron Eldreth8-Jun-04 10:20 
GeneralRe: Nice Colin! Pin
Megan Forbes8-Jun-04 21:59
Megan Forbes8-Jun-04 21:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.