User Interface Text, Languages and Themes

Every piece of text the Rule Repository shows (tab names, column headings, buttons, dialog titles, messages, the names of months and weekdays) comes from one XML document, the user interface XML. The repository ships an English one. You can translate it to run the repository in another language, or reword it to match your organization's vocabulary, without changing any code.

This page explains how the document is organized, how to translate or reword it, how to give each user their own language, what to do when a new release adds text, and where the repository's other presentation settings are: dates, themes, layout and the links to this documentation.

Two more documents complete a translation: the rule editors' Help XML (their menus, operators and Help String) and the source labels (the names of your source objects' fields, methods and actions). Both are set on the same configuration; see The Rule Editors and the Source Objects below.

How the Text Reaches the Page

No text is built into codeeffects.repository.js. When a page opens, the client's first request (Init) asks your endpoint for the markup and the text, and Context.GetResponse(..) answers with the text from the document your request configuration names, or the default English one. So the language is decided on the server, per request, by your application, and the client needs no setting.

The server's own messages (refusals, confirmations, warnings) come from the same document, so a translation covers them too.

The Document

<codeeffects>
	<labels>
		<l101>Source Objects</l101>
		...
	</labels>
	<messages>
		<m111>Page {page} of {total}</m111>
		...
	</messages>
	<enums>...</enums>
	<dates>...</dates>
	<tips>...</tips>
</codeeffects>
Section Node names Holds
labels l + three digits Tab and dialog names, column headings, field captions, buttons, the grey text of empty filters
messages m + three digits Whole sentences: empty grids, explanations, confirmations, what a button says while it waits
enums e + three digits The name of every value the repository shows by name, such as a status or an activity type
dates d + three digits Months, weekday headings, the ready-made date ranges
tips t + three digits Tooltips, and what screen readers read out

Placeholders are named, such as {page} and {total}, so a translation can move them anywhere in the sentence. Keep every placeholder exactly as written.

Translating or Rewording

  1. Get the default document. Context.GetDefaultUiXml() returns it as an XmlDocument: a new copy on every call. Save it once, for example from a small console tool or a test:

     using CodeEffects.Rule.Repository;
    
     Context.GetDefaultUiXml().Save("Repository.ui.en-US.xml");
    
  2. Translate the text between the tags. Change nothing else. Keep every node, its name and its section. Do not add or remove nodes.

  3. Give the result to the repository, on every request's configuration, in one of two ways:

    Property Takes Notes
    UiXml An XmlDocument Wins when both are set. Ignored when null or without a root element.
    UiXmlFile The full physical path to the file, not a virtual path or a URL Read when a page loads and when a server message is built
     var config = new Configuration
     {
     	// ...
     	UiXmlFile = Path.Combine(env.ContentRootPath, "App_Data", "Repository.ui.de-DE.xml")
     };
    

Your document replaces the default one entirely; it is not merged with it. That is why it must declare every node the default declares.

The repository checks your document at the first request that uses it and refuses it, with a message for your developers, if it is not complete:

Control number What is wrong
CE10060 The file could not be read, or is not well-formed XML. The path is not in the message, which reaches the browser; it is on the inner exception for your log
CE10061 The root element is not codeeffects
CE10062 A section is missing
CE10063 A node the default declares is missing. A misspelled node shows as this, and the message also names the unknown node
CE10064 A node is in the wrong section, or declared twice
CE10065 A node is empty

A parsed document is cached by its content, so building a configuration on every request costs one parse per document, not one per request.

A Language for Each User

Keep one translated file per language and choose it from the signed-in user's preference or the request's culture:

public static class RepositoryLanguages
{
	private static readonly string[] Supported = { "de-DE", "fr-FR", "es-ES" };

	/// <summary>The user interface file for a culture, or null for the built-in English.</summary>
	public static string FileFor(string contentRoot, string culture)
	{
		var match = Supported.FirstOrDefault(c => string.Equals(c, culture, StringComparison.OrdinalIgnoreCase));
		return match == null ? null : Path.Combine(contentRoot, "App_Data", "Repository.ui." + match + ".xml");
	}
}

// In the endpoint
var culture = http.Features.Get<IRequestCultureFeature>()?.RequestCulture.UICulture.Name ?? "en-US";

var config = new Configuration
{
	// ...
	UiXmlFile = RepositoryLanguages.FileFor(env.ContentRootPath, culture)
};

A folder per language that holds all three documents keeps this simple:

// App_Data/Translations/de-DE/Repo.xml, RuleHelp.xml and Labels.xml; null (English) when a file is not there
string In(string file)
{
	var path = Path.Combine(env.ContentRootPath, "App_Data", "Translations", culture, file);
	return File.Exists(path) ? path : null;
}

var config = new Configuration
{
	// ...
	UiXmlFile = In("Repo.xml"),
	EditorHelpXmlFile = In("RuleHelp.xml"),
	SourceLabelsXmlFile = In("Labels.xml")
};

Dates are formatted in the browser: set the client's locale option of $repo.init(..) to the same culture so the repository's dates match its text. Without it, the browser's own language is used.

const repository = $repo.init({ id: "rules", requestCallback: request, locale: "de-DE" });

The Rule Editors and the Source Objects

The repository's own text is only part of what your users read. Two more documents translate the rest, both set on the same configuration:

What Property The English to translate
The rule editors inside the repository: menus, operators, clauses, flow words, the Help String EditorHelpXml or EditorHelpXmlFile Context.GetDefaultEditorHelpXml()
The source objects: the names and descriptions of their fields, in-rule methods, actions, parameters and enumeration values SourceLabelsXml or SourceLabelsXmlFile Xml.GetSourceLabelsDocument(..)

The source labels name each member by its identity (a field by its property path, a method or action by its name and parameters, a value by its enumeration and number), never by its display name, so one document serves every version of a source. The repository lays them over a source version wherever people read it: the rule editors and the Source Fields tab. Stored source versions and rules never change: a rule saved by a German user opens in English for the next one. AI agents keep working with the source's own names and are given the labels beside them, so a user can name a field in their own language. A member the labels leave out shows its own name. See Help XML and Multilingual Support for the document's format.

A file that cannot be read fails the request with CE10262 (the editors' Help XML) or CE10263 (the source labels).

What Stays as Stored or in English

  • Names people write: rule and version names, descriptions, notes, test names, the users' names, and the source object's name in the grids, which is stored when the source is synchronized. They are shown as they were written.
  • The heading of the delete confirmation (Danger Zone).
  • The text given to AI agents and the AI Assistant: tool descriptions and server messages agents read are always the default English, whatever document your users see. Users can still write to the Assistant in their own language.
  • The Message of notifications raised through Notify, which is the activity log's English sentence.

When a New Release Adds Text

New features bring new nodes. A translation made for an earlier release lacks them, and the repository refuses it with CE10063, naming the missing node, until it is complete. Plan for this in every upgrade:

  1. Save the new release's default document with Context.GetDefaultUiXml().
  2. Compare it with the default you translated from last time. Every node that is new or changed needs translating.
  3. Add the new nodes to each of your translations, in the same section, and translate them.
  4. Test each translation by loading the repository once in that language before you deploy.

Keep the English default each translation was made from in source control next to it; the comparison is then a plain text diff.

Themes, Layout and the Client's Presentation Options

The rest of the repository's appearance is set on the page, not on the server:

What Where
Light or dark theme, colours, fonts and sizes The stylesheets; see CSS Styles
The first grid shown, page sizes, the phone layout's width, the filter delay, animations $repo.init(..) options defaultView, pageSizes, defaultPageSize, mobileBreakpoint, filterDelay, animations
Display settings of the Rule Editors inside the repository The editor option: showHelpString, showLineDots, showDescriptionsOnMouseHover, showMenuOnElementClicked, showMenuOnRightArrowKey
Links to the Code Effects documentation The help option; set it to false to hide every link
Where messages appear The notifyCallback option shows them in your page's own notification style
const repository = $repo.init({
	id: "rules",
	requestCallback: request,
	defaultView: "ruleVersions",
	pageSizes: [10, 25, 50],
	defaultPageSize: 25,
	help: false,
	editor: { showLineDots: true }
});

All options are described on the codeeffects.repository.js page.

Ask on Stack Overflow - Yes, it's still active
Ask in GitHub Discussions

p102

l097 --

l102

p101

×