https://techbase.kde.org/api.php?action=feedcontributions&user=Smileaf&feedformat=atomKDE TechBase - User contributions [en]2024-03-28T08:04:55ZUser contributionsMediaWiki 1.40.2https://techbase.kde.org/index.php?title=Development/Tutorials/Localization/i18n&diff=12894Development/Tutorials/Localization/i18n2007-08-12T02:55:40Z<p>Smileaf: /* Adding Context */</p>
<hr />
<div>{{TutorialBrowser|<br />
<br />
series=Localization|<br />
<br />
pre=[[../Unicode|Introduction to Unicode]] is recommended, though not required|<br />
<br />
name=Writing Applications With Localization In Mind|<br />
<br />
next=[[../i18n_Mistakes|Avoiding Common Localization Pitfalls]]|<br />
<br />
}}<br />
<br />
== Abstract ==<br />
<br />
Reaching a broad audience of users and developers requires that your software can be translated and otherwise shaped at runtime to be linguistically and culturally relevant to whomever is sitting in front of the computer. This is the realm of localization and this tutorial steps you through what is needed to make your application localizable.<br />
<br />
== What is Internationalization and Localization? ==<br />
<br />
Internationalization, or i18n ('i', followed by 18 letters, then an 'n'), is the process of writing your application so that it can be run in any locale. This means taking into account such things as:<br />
* textual messages that are displayed to the user<br />
* data input from the user, files and other sources<br />
* format of dates, numbers, currency, dates, etc.<br />
<br />
Localization, or l10n ('l', followed by 10 characters, then an 'n'), is the process of taking an internationalized application and adapting it for a specific locale.<br />
<br />
Generaly speaking, programmers internationalize their applications and translation teams localize them.<br />
<br />
== Why is This Important? ==<br />
<br />
KDE development happens primarily in English as this allows the broadest reach into the development and translation communities. However, English is not the primary language of most people on the planet. In fact, fewer than 8% of humanity speaks English and less than 5% speak it as their mother tongue. Even on the Internet, only 35% people who are online use English as their primary language and as more and more of the world gets wired this number is only decreasing. Additionally most languages, including 9 out of the 10 most common languages, use non-ASCII characters in their written form. It is easy to see, then, why it has become a necessity to provide localized software. <br />
<br />
As an international project that spans the globe, such localization is a core value within the KDE culture. In fact, while many KDE developers write their software in English they use the desktop in their native locale.<br />
<br />
== Translatable Code Using i18n() ==<br />
<br />
To ensure your application is ready to be localized you have to follow a few simple rules. All user-visible strings in your application should be translated before they are displayed on the user's screen, exceptions to this being debugging messages, configuration keys and similar types of text data.<br />
<br />
KDE provides the <tt>KLocale</tt> class as part of <tt>libkdecore</tt> to facilitate the technical details of localization. KLocale makes it as easy as possible for developers to make their code i18n aware, but there are some things you need to be aware of so that applications are usable in other languages and countries.<br />
<br />
Access to a global <tt>KLocale</tt> object is provided via <tt>KGlobal::locale()</tt>. This <tt>KLocale</tt> object is created automatically by <tt>KInstance</tt> and takes care of all user i18n related settings. It is deleted automatically on application exit.<br />
<br />
Translations are made possible by the <tt>QString i18n(const char*)</tt> method, defined in <tt>klocalizedstring.h</tt>, which you must wrap all strings that should be displayed in. The QString returned by <tt>i18n()</tt> is the translated (if necessary) string. This makes creating translatable widgets as simple as in this example:<br />
<br />
<code cppqt><br />
#include <klocalizedstring.h><br />
[...]<br />
QPushButton* myButton = new QPushButton(i18n("Translate this!"));</code><br />
<br />
QString's native Unicode support ensures that all translations are represented correctly. All string handling done by your application should therefore use QString.<br />
<br />
{{tip|If the string to be translated contains any non-UTF8 characters, use the utf8() method to get a char*.}}<br />
<br />
=== ki18n ===<br />
<br />
The <tt>i18n()</tt> method requires that a <tt>KInstance</tt> (e.g. <tt>KApplication</tt>) has been created. For any strings that are created prior to this there is another method provided: <tt>ki18n()</tt>. This allows one to mark strings that should be translated later as such. The ki18n() will return a <tt>KLocalizedString</tt>, which can be finalized into a QString (i.e. translated for real) after the KInstance has been created, using its toString() method.<br />
<br />
ki18n() is typically used for strings given to KAboutData, because it is constructed before the KApplication and you can use i18n() only after the construction of the KApplication. Other than these special cases, it is always safe to use i18n() if you are sure that the code will be executed after construction of KApplication or some other KInstance.<br />
<br />
=== Adding Context ===<br />
<br />
There is an extended version of <tt>i18n()</tt>, <tt>i18nc()</tt> which takes two <tt>const char*</tt> arguments. The first argument is an additional contextual description of the second string which will be translated. The first string is used to find the proper corresponding translation at run-time and is shown to translators to help them understand the meaning of the string. <br />
<br />
Use <tt>i18nc()</tt> whenever the purpose of the text might be ambiguous without further context. For example, consider a context menu in a file manager with an entry called "View" which opens a viewer for the currently selected file. In this context "View" is a verb. However, the same application also may have a menu called "View" in the menubar. In that context "View" is a noun. In the English version of the application everything looks fine, but in most other languages one of the two "View" strings will be incorrect.<br />
<br />
Additionally, translators sometimes need extra help in understanding what the text is actually referring to during the translation process.<br />
<br />
In the file manager example above, one might therefore write:<br />
<br />
<code cppqt>contextMenu->addAction(i18nc("verb, to view something", "View"));<br />
viewMenu->addAction(i18nc("noun, the view", "View"));</code><br />
<br />
Now the two strings will be properly translatable, both by the human translators and at runtime by KLocale.<br />
<br />
Use this form of i18n whenever the string to translate is short or the meaning is hard to discern when the context is not exactly known. For example:<br />
<br />
<code cppqt>QString up = i18nc("Go one directory up in the hierarchy", "Up");<br />
QString relation = i18nc("A person's name and their familial relationship to you.", "%1 is your %2", name, relationship);</code><br />
<br />
{{note|There is also a ki18nc("context","text") method for providing context to strings which are constructed before the KInstance. It returns a KLocalizedString, so use the toString() method afterwards to convert it into a QString.}}<br />
<br />
Contexts can also be added when building forms in Qt Designer. Each widget label, including tooltips and whatsthis texts, has a "comment" attribute, which will serve the same purpose as first argument to <tt>i18nc()</tt> call.<br />
<br />
=== Standard Context For Common Phrases ===<br />
<br />
Below is a chart showing some common words and phrases in English and the context that must be used with them to ensure proper translation of them in other languages.<br />
<br />
{|<br />
|+ Standard Contexts<br />
|-<br />
! Phrase !! Context !! i18nc Call !! Example<br />
|-<br />
| Busy || Refering to a person || <tt>i18nc("A person is busy", "Busy")</tt><br />
|-<br />
| Busy || Refering to a thing || <tt>i18nc("A thing is busy", "Busy")</tt><br />
|-<br />
| Color || Color mode, as opposed to Grayscale || <tt>i18nc("Color mode", "Color")</tt><br />
|-<br />
| Creator || Refering to a person || <tt>i18nc("A person who creates", "Creator")</tt><br />
|-<br />
| Creator || Refering to software || <tt>i18nc("Software", "Creator")</tt><br />
|-<br />
| Display || Refering to hardware || <tt>i18nc("Hardware display", "Display")</tt><br />
|-<br />
| Editor || Refering to a person || <tt>i18nc("A person who edits", "Editor")</tt><br />
|-<br />
| Editor || Refering to software || <tt>i18nc("Software", "Editor")</tt><br />
|-<br />
| Line || Refering to drawing || <tt>i18nc("Draw a line", "Line")</tt><br />
|-<br />
| Line || Refering to text || <tt>i18nc("Line of text", "Line")</tt><br />
|-<br />
| Name || Refering to a name of thing || <tt>i18nc("A thing's name", "Name") || In theme change dialog: i18nc("Theme name", "Name")</tt><br />
|-<br />
| Name || Refering to first name and last name of person || <tt>i18nc("Person's first and last name", "Name") || In KAddessbook contact edit dialog: i18nc("Person's first and last name", "Name")</tt><br />
|-<br />
| No || Answer to a question || <tt>i18nc("Answer to a question", "No")</tt><br />
|-<br />
| No || Availability of a thing || <tt>i18nc("Availability", "No")</tt><br />
|-<br />
| (Re)load || (Re)load a document, medium etc. || <tt>i18nc("(Re)load a document", "(Re)load")</tt><br />
|-<br />
| (Re)load || (Re)start a program, daemon etc. || <tt>i18nc("(Re)start a program", "(Re)load")</tt><br />
|-<br />
| Title || Refering to a person || <tt>i18nc("A person's title", "Title")</tt><br />
|-<br />
| Title || Refering to a thing || <tt>i18nc("A thing's title", "Title")</tt><br />
|-<br />
| Volume || Refering to sound || <tt>i18nc("Sound volume", "Volume")</tt><br />
|-<br />
| Volume || Refering to a filesystem || <tt>i18nc("Filesystem volume", "Volume")</tt><br />
|-<br />
| Volume || Refering to books || <tt>i18nc("Book volume", "Volume")</tt><br />
|-<br />
| Yes || Answer to a question || <tt>i18nc("Answer to a question", "Yes")</tt><br />
|-<br />
| Yes || Availability of a thing|| <tt>i18nc("Availability", "Yes")</tt><br />
|}<br />
<br />
=== Plurals ===<br />
<br />
Plurals are handled differently from language to language. Many languages have different plurals for 2, 10, 20, 100, etc. When the string you want translated refers to more than one item, you must use the third form of <tt>i18n</tt>, the <tt>i18np()</tt>. It takes the singular and plural English forms as its first two arguments, followed by any substitution arguments as usual, but at least one of which should be integer-valued. For example:<br />
<br />
<code cppqt>msgStr = i18np("1 image in album %2", "%1 images in album %2", numImages, albumName);</code><br />
<br />
<tt>i18np()</tt> gets expanded to as many cases as required by the user's language. In English, this is just two forms while in other languages it may be more, depending on the value of the first integer-valued argument.<br />
<br />
Note that this form should be used even if the string always refers to more than one item as some languages use a singular form even when referring to a multiple (typically for 21, 31, etc.). This code:<br />
<br />
<code cppqt>i18n("%1 files were deleted", numFilesDeleted);</code><br />
<br />
is therefore incorrect and should instead be:<br />
<br />
<code cppqt>i18np("1 file was deleted", <br />
"%1 files were deleted",<br />
numFilesDeleted);</code><br />
<br />
To provide context as well as pluralization, use <tt>i18ncp</tt> as in this example:<br />
<br />
<code cppqt>i18ncp("Personal file", "1 file", "%1 files", numFiles);</code><br />
<br />
== Formatting Dates and Numbers ==<br />
<br />
When displaying a number to the user, your program must take care of the decimal separator, thousand separator and currency symbol (if any) being used. These symbols differ from region to region. In English speaking countries a dot (.) is used to separate the fractional part of a number, while in some European countries a comma (,) is used instead. Below is a short summary of functions that will help you format the numbers correctly, taking the local conventions into account for you.<br />
<br />
{|<br />
|+ Functions to Format Numbers<br />
|-<br />
! Formats&nbsp;a.. !! From&nbsp;a.. !! Function&nbsp;Prototype<br />
|-<br />
| Number || String || <pre>QString formatNumber( const QString & numStr )</pre><br />
|-<br />
| Number || Integer,&nbsp;double || <pre>formatNumber( double num, <br />
int precision = -1 )</pre><br />
|-<br />
| Money || String || <pre>formatMoney( const QString & numStr )</pre><br />
|-<br />
| Money || Number || <pre>formatMoney( double num, <br />
const QString & currency,<br />
int digits = -1 )</pre><br />
|-<br />
| Date || String || <pre>formatDate( const QDate & pDate,<br />
bool shortFormat=false )</pre><br />
|-<br />
| Time || QTime || <pre>formatTime( const QTime & pTime, <br />
bool includeSecs=false)</pre><br />
|-<br />
| Date&nbsp;and&nbsp;time || QDateTime || <pre>formatDateTime( const QDateTime &pDateTime,<br />
bool shortFormat = true,<br />
bool includeSecs = false )</pre><br />
|} <br />
<br />
Similar functions exist to read information provided by the user at runtime in their localized format, e.g. readNumber() or readMoney().<br />
<br />
== Calendaring ==<br />
<br />
Developing applications dealing with dates and time, such as calendars, is a very complex area. Not only may the displayed string containing a date or time may look different based on locale, but one also has to take care of other aspects such as:<br />
* which day in the week is the first one (cf int weekStartDay()) <br />
* how many months in a year there are <br />
* "era"-based calendars <br />
* whether to use 24-hour time format (cf bool use12Clock()) <br />
<br />
KLocale provides, among others, these methods: <br />
<br />
{|<br />
|+ Calendar Data Functions<br />
|- <br />
! Formats&nbsp;a.. !! From&nbsp;a.. !! Function Prototype<br />
|-<br />
| Date || QDate || <pre>formatDate( const QDate & pDate,<br />
bool shortFormat=false )</pre><br />
|-<br />
| Time || QTime || <pre>formatTime( const QTime & pTime,<br />
bool includeSecs=false )</pre><br />
|-<br />
| Date&nbsp;and&nbsp;time || QDateTime || <pre>formatDateTime( const QDateTime &pDateTime,<br />
bool shortFormat=true,<br />
bool includeSecs=false )</pre><br />
|}<br />
<br />
{{improve|provide more info on the different calendar systems}}<br />
<br />
== Avoiding Common Traps ==<br />
There are a number of common problems that may prevent an application being properly localized. See [[../i18n Mistakes|Avoiding Common Localization Pitfalls]] to learn more about them, and how to avoid them.<br />
<br />
{{note|Thanks to Lukáš Tinkl, Matthias Kiefer and Gary Cramblitt for writing the original version of this tutorial.}}<br />
<br />
[[Category:Programming]]</div>Smileafhttps://techbase.kde.org/index.php?title=Development/Tutorials/Localization/i18n_Krazy&diff=12893Development/Tutorials/Localization/i18n Krazy2007-08-12T02:54:52Z<p>Smileaf: fixing grammar.</p>
<hr />
<div>== Abstract ==<br />
<br />
There are small technical details of i18n which are not that easy to keep in mind at all times, as well as number of i18n recommendations to uphold during the development. To help you with this, the [[Development/Tutorials/Code_Checking|Krazy code checker]] also looks for some frequently encountered i18n issues. This article documents these issues as reported by Krazy, for cases when you are not sure what the remedy should be.<br />
<br />
== Placeholders and Arguments ==<br />
<br />
The i18n API is very strict about congruence between the <tt>%''number''</tt> placeholders in the message, and the arguments actually supplied to substitute them. Effectively, the placeholders directly index arguments, albeit one- rather than zero-based.<br />
<br />
; <tt>"wrong argument count, have ''num1'' need ''num2''"</tt><br />
:: Either some of the arguments have not been provided, or there is a stray placeholder inside the message string. A likely cause is forgetting that in KDE4, arguments are added as parameters to the i18n call itself, rather than appended via <tt>arg()</tt> methods as in KDE3:<br />
<code cpp><br />
i18n("Found key: %1", key); // correct<br />
i18n("Found key: %1").arg(key); // ***wrong<br />
</code><br />
<br />
; <tt>"too many arguments, have ''num'' max 9"</tt><br />
:: i18n calls can take at most 9 arguments as parameters to the call. If more than that is needed, the <tt>ki18n*()</tt> series of calls must be used, see the documentation to {{class|KLocalizedString}} class. The calls with more than 9 parameters are extremely rare, though.<br />
<br />
; <tt>"gaps in placeholder numbering, ..."</tt><br />
:: Except in case of plural i18n calls, there must be no gaps in placeholder sequence, starting from <tt>%1</tt>. In plural calls, the placeholder of the first number (which determines plural) form, may be omitted, both in singular and plural:<br />
<code cpp><br />
i18n("Line: %1 Column: %2", lineNo, colNo); // correct<br />
i18n("Line: %1 Column: %3", lineNo, colNo); // ***wrong<br />
<br />
i18np("Found a file in folder %2",<br />
"Found %1 files in folder %2", nfiles, folder); // correct<br />
i18np("Found a file in folder %2",<br />
"Found some files in folder %2", nfiles, folder); // also correct<br />
i18np("Found a file in folder %1",<br />
"Found some files in folder %1", folder, nfiles); // ***wrong<br />
</code><br />
<br />
; <tt>"legacy %n placeholder in plural call"</tt><br />
:: This is a remnant from KDE3, where in plural i18n calls, the argument determining the plural form had special <tt>%n</tt> placeholder. In KDE4, all arguments have ordinary <tt>%''number''</tt> placeholders, as in the examples above (the plural form is decided upon the lowest-numbered argument that is an integer).<br />
<br />
== Ambiguous Short Messages ==<br />
<br />
English is a rather noninflected language compared to many others; single English word can frequently be noun, verb, or adjective, while retaining its original form. This presents frequent problems for the translator while translating into inflected languages when the original message is short, especially single-worded. The solution is to [[Development/Tutorials/Localization/i18n#Adding_Context|add context]] to the message via <tt>i18nc()</tt> call.<br />
<br />
; <tt>"single adjective as message, probably ambiguous; ..."</tt><br />
:: Words that can be treated as adjectives are especially prone to ambiguities. Therefore Krazy checks single-worded messages against a list of adjectives collected from the KDE codebase, and issues this warning if the matching message does not have a context. For example:<br />
<code cpp><br />
titleFinal = title.isEmpty() ?<br />
i18n("Unknown") : title; // ambiguous<br />
titleFinal = title.isEmpty() ?<br />
i18nc("An unknown title", "Unknown") : title; // clarified<br />
</code><br />
<br />
; <tt>"reported ambiguous message by translators; ..."</tt><br />
:: There are other troublesome words, or even phrases, which were explicitly reported by translators as ambiguous. This warning means that such a message without context has been detected.<br />
<br />
While you are at adding contexts, consider providing the appropriate [[Development/Tutorials/Localization/i18n_Semantics#Context_Markers|KUIT context marker]] as well, which will further zero-in translators' job:<br />
<code cpp><br />
titleFinal = title.isEmpty() ?<br />
i18nc("@item:intable An unknown title", "Unknown") : title;<br />
// way to go!<br />
</code><br />
<br />
== Number Formatting ==<br />
<br />
The number-valued (either integer or real) arguments to i18n messages are formatted automatically into given language, without programmer's intervention. Using other methods to format numbers into strings may circumvent proper formatting for the language.<br />
<br />
; <tt>"use of QString::number() on an argument"</tt><br />
:: <tt>QString::number()</tt> should never be used to format "amount" numbers, because within KDE code it will do so using English conventions. However, sometimes the number is not an amount, e.g. port number 15000 should not be formatted as "15,000" in English; use <tt>&lt;numid&gt;</tt> KUIT tag in this situation:<br />
<code cpp><br />
i18n("Number of pages: %1", numPages); // good, localized amount format<br />
i18n("Connected to port %1.", port); // bad, amount format not desired<br />
i18n("Connected to port %1.", QString::number(port)); // bad, not localized<br />
i18n("Connected to port <numid>%1</numid>.", port); // good<br />
</code><br />
<br />
;; <tt>"use of KLocale::formatNumber() on an argument (...)"</tt><br />
:: A smarter way to format numbers is using <tt>KLocale::formatNumber()</tt>, which will honor user's settings. However, then the format cannot be decided upon the language of the particular message in question (some applications may not have translations), so it's best avoided in i18n arguments. Use it for "live numbers", e.g. in spreadsheet tables and calculator displays, where the format should match user's number-typing habit.<br />
<br />
Even when the complete message is a single number, it should be i18n'd, with a proper context:<br />
<code cpp><br />
result = QString::number(z); // bad<br />
result = i18nc("Atomic number", "%1", z); // good<br />
</code><br />
<br />
When the number is to be formatted in a special way (field width, number of decimals, etc.) into the message, still neither <tt>QString::number()</tt> nor <tt>KLocale::formatNumber()</tt> should be used, but <tt>ki18n*()</tt> series of calls with <tt>subs()</tt> methods (see {{class|KLocalizedString}} documentation):<br />
<code cpp><br />
i18n("Percent complete: %1", QString::number(percent, 'f', 1)); // bad<br />
ki18n("Percent complete: %1").subs(percent, 0, 'f', 1).toString(); // good<br />
</code><br />
<br />
== HTML and KUIT Markup ==<br />
<br />
Every i18n message in KDE4 is effectively XML markup. HTML tags come from Qt's rich text, and can be used only in rich-text capable widgets; KUIT tags are new KDE4 [[Development/Tutorials/Localization/i18n_Semantics|semantic markup]], which should be preferred to HTML, and can be used in ''any'' i18n message (plain or rich-text output is decided on the basis of [[Development/Tutorials/Localization/i18n_Semantics#Context_Markers|context marker]]).<br />
<br />
; <tt>"malformed markup (unmatched tags, etc.)"</tt><br />
:: Since every message is XML, all tags must be properly closed. Opening <tt>&lt;p&gt;</tt> must not miss closing <tt>&lt;/p&gt;</tt>, etc. This also holds for breaking HTML tags like <tt>&lt;br&gt;</tt> and <tt>&lt;hr&gt;</tt>, which must be closed in place: <tt>&lt;br/&gt;</tt>, <tt>&lt;hr/&gt;</tt>.<br />
<br />
: Verbatim greater-than sign means opening of a tag, which is not always meant. This can be avoided by use of predefined XML <tt>&amp;lt;</tt> entity (other predefined entities are <tt>&amp;gt;</tt>, <tt>&amp;amp;</tt>, <tt>&amp;apos;</tt>, and <tt>&amp;quot;</tt>), but for a frequent case of marking generic or user-replaceable text, it is better to use <tt>&lt;placeholder&gt;</tt> KUIT tag:<br />
<code cpp><br />
i18n("headers go into <includes>"); // ***error in XML markup<br />
i18n("headers go into &lt;includes&gt;"); // no markup problem, but...<br />
i18n("headers go into <placeholder>includes</placeholder>"); // better<br />
</code><br />
<br />
: Given it's frequency, it is not needed to use <tt>&amp;amp;</tt> for shortcut markers; there is some heuristics around XML parsing to allow presence of naked &amp;. Basically, <tt>&amp;amp;</tt> is needed only in the rare case of <tt>&amp;''no_whitespace_sequence'';</tt> pattern which is ''not'' meant as an XML entity.<br />
<br />
; <tt>"unclosed &lt;br&gt; ... use proper paragraphs &lt;p&gt;...&lt;/p&gt; instead"</tt><br />
:: This just signals a particularly frequent markup problem, that of <tt>&lt;br&gt;</tt> not closed in place, like <tt>&lt;br/&gt;</tt>. Also, sometimes <tt>&lt;br&gt;</tt> is used to split logical paragraphs (especially when doubled, <tt>&lt;br&gt;&lt;br&gt;</tt>), where proper paragraph tags should be used instead.<br />
<br />
; <tt>"''tag'' is neither KUIT nor HTML tag"</tt><br />
:: Some of the tags in the message is simply unknown, and will not be understood at runtime. If it is not a typo, but the message is really speaking about tags to the user (e.g. in a HTML editing application), use <tt>&amp;lt;foo&amp;gt;</tt> pattern.<br />
<br />
; <tt>"HTML tag ''tag'' is not advised with KUIT markup"</tt><br />
:: When Krazy encounters the KUIT context marker in a message, it assumes that message is semantically tagged, and disapproves of some HTML tags which are best replaced with semantic equivalents. For example:<br />
<code cpp><br />
i18n("@info:whatsthis",<br />
"...this <i>cannot</i> be undone."); // Krazy complains<br />
i18n("@info:whatsthis",<br />
"...this <emphasis>cannot</emphasis> be undone."); // fine<br />
<br />
i18n("@info",<br />
"Really delete <b>%1</b>?", filename); // complains<br />
i18n("@info",<br />
"Really delete <filename>%1</filename>?", filename); // fine<br />
</code><br />
<br />
; <tt>"tag ''tag1'' cannot be subtag of ''tag2''"</tt><br />
; <tt>"tag ''tag'' has no ''att'' attribute"</tt><br />
; <tt>"tag ''tag'' cannot have text content"</tt><br />
:: These are validity checks for KUIT markup, a bit relaxed form of formal XML validation. The rules of which KUIT tag can contain which, and so on, are given with [[Development/Tutorials/Localization/i18n_Semantics#Semantic_Tags|tag descriptions]].<br />
<br />
== KUIT Context Markers ==<br />
<br />
Semantic [[Development/Tutorials/Localization/i18n_Semantics#Context_Markers|context markers]] give great deal of information to translators of where and how the message is used at runtime. Providing them for ''any'' future messages is strongly encouraged, and even equipping existing messages when not in message freeze is welcomed. Krazy helps with the following checks.<br />
<br />
; <tt>"missing KUIT context marker"</tt><br />
:: If Krazy detects that the source file has a number of messages equipped with KUIT context markers, above some threshold, it assumes that developer's intention was to have all messages marked (as is recommended), and issues this warning for any non-marked message.<br />
<br />
; <tt>"invalid semantic role ''role''"</tt><br />
; <tt>"invalid interface subcue ''cue'' to role ''role''"</tt><br />
; <tt>"invalid visual format ''fmt''"</tt><br />
:: Krazy checks that all ingredients of the context marker are defined, and that a particular combination of them is valid.<br />
<br />
; <tt>"expected context marker ''ctxmark1'', got ''ctxmark2''"</tt><br />
:: For messages used in some boiler-plate situations, canonical context markers have been established. Krazy warns if the context marker to such a message, although valid by itself, was not the expected one. For example, such messages are encountered in setting up the {{class|KAboutData}} information.<br />
<br />
== Contact ==<br />
<br />
For any questions or suggestions, Krazy i18n checks are presently maintained by Chusslove Illich &lt;caslav.ilic@gmx.net&gt;.</div>Smileaf