PostSharpContractsLocalizing Contract Error Messages
Open sandboxFocusImprove this doc

Localizing Contract Error Messages

You can customize all texts of exceptions raised by built-in contract. This allows you to localize error messages into different languages.

Contracts use the ContractLocalizedTextProvider class to obtain the text of an error message. This class follows a simple chain of responsibilities pattern where each provider has a reference to the next provider in the chain. When a message is queried, the provider either returns a message or passes control to the next provider in the chain.

Each message is identified by a string identifier and can refer to 4 basic arguments and additional arguments specific to a message type. For general information about message arguments please see remarks section of LocationContractAttribute. To find the identifier of a particular message and its additional arguments, please see remarks section of contract classes in PostSharp.Patterns.Contracts.

Localizing a built-in error message

Following steps illustrate how to override an error message of a given contract:

To override a contract error message:

  1. Declare a class that derives from ContractLocalizedTextProvider and implement the chain constructor.

    public class CzechContractLocalizedTextProvider : ContractLocalizedTextProvider
    {
        public CzechContractLocalizedTextProvider(ContractLocalizedTextProvider next)
          : base(next)
        {
        }
    
    }
    
  2. Implement the GetMessage(String) method. In the next code snippet, we show how to build a simple and efficient dictionary-based implementation.

    public class CzechContractLocalizedTextProvider : ContractLocalizedTextProvider
    {
          private readonly Dictionary<string, string> messages = new Dictionary<string, string>
                                        {
                                            {RegularExpressionErrorMessage, "Hodnota {2} neodpovídá regulárnímu výrazu '{4}'."},
                                        };
    
        public CzechContractLocalizedTextProvider(ContractLocalizedTextProvider next)
          : base(next)
        {
        }
    
        public override string GetMessage( string messageId )
        {
            if ( string.IsNullOrEmpty( messageId ))
                throw new ArgumentNullException("messageId");
    
            string message;
            if ( this.messages.TryGetValue( messageId, out message ) )
            {
                return message;
            }
            else
            {
                // Fall back to the default provider.
                return base.GetMessage( messageId );
            }
        }
    }
    
    Note

    If you need to support several languages, you can make your implementation of the GetMessage(String) method depend on the value of the CurrentCulture property. You can optionally store your error messages in a managed resource and use the ResourceManager class to access it and manage localization issues. The design of PostSharp Code Contracts is agnostic to these decisions.

  3. In the beginning of an application, create a new instance of the provider and set the current provider as its successor.

    public static void Main()
    {
        ContractServices.LocalizedTextProvider = new CzechContractLocalizedTextProvider(ContractServices.LocalizedTextProvider);
    
        // ...
    }
    

Localizing custom contracts

Once you have configured a text provider, you can use it to localize error messages of custom contracts. In the following procedure, we will localize the error message of the example contract described in Creating Custom Contracts.

To localize a custom contract:

  1. Edit the code contract class (NonZeroAttribute in our case) to call ContractServices.ExceptionFactory.CreateException() in the validation method(s), as shown in Customizing Contract Exceptions. Use a unique messageId (e.g. "NonZeroErrorMessage") to identify the message text template.

  2. Edit your implementation of the LocalizedTextProvider class and include the message for your custom contract:

    private readonly Dictionary<string, string> messages = new Dictionary<string, string>
    {
       {RegularExpressionErrorMessage, "Hodnota {2} neodpovídá regulárnímu výrazu '{4}'."},
       {"NonZeroErrorMessage", "Hodnota {2} nesmí být 0."}
    };