You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
594 lines
22 KiB
594 lines
22 KiB
/****************************************************************************
|
|
**
|
|
** Explanation of moc and the meta object system
|
|
**
|
|
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
|
|
**
|
|
** This file is part of the TQt GUI Toolkit.
|
|
**
|
|
** This file may be used under the terms of the GNU General
|
|
** Public License versions 2.0 or 3.0 as published by the Free
|
|
** Software Foundation and appearing in the files LICENSE.GPL2
|
|
** and LICENSE.GPL3 included in the packaging of this file.
|
|
** Alternatively you may (at your option) use any later version
|
|
** of the GNU General Public License if such license has been
|
|
** publicly approved by Trolltech ASA (or its successors, if any)
|
|
** and the KDE Free TQt Foundation.
|
|
**
|
|
** Please review the following information to ensure GNU General
|
|
** Public Licensing requirements will be met:
|
|
** http://trolltech.com/products/qt/licenses/licensing/opensource/.
|
|
** If you are unsure which license is appropriate for your use, please
|
|
** review the following information:
|
|
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
|
|
** or contact the sales department at sales@trolltech.com.
|
|
**
|
|
** This file may be used under the terms of the Q Public License as
|
|
** defined by Trolltech ASA and appearing in the file LICENSE.QPL
|
|
** included in the packaging of this file. Licensees holding valid Qt
|
|
** Commercial licenses may use this file in accordance with the Qt
|
|
** Commercial License Agreement provided with the Software.
|
|
**
|
|
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
|
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
|
** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
|
|
** herein.
|
|
**
|
|
**********************************************************************/
|
|
|
|
/*! \defgroup i18n
|
|
|
|
\title Internationalization with Qt
|
|
|
|
\keyword internationalization
|
|
\keyword i18n
|
|
|
|
The internationalization of an application is the process of making
|
|
the application usable by people in countries other than one's own.
|
|
|
|
\tableofcontents
|
|
|
|
In some cases internationalization is simple, for example, making a US
|
|
application accessible to Australian or British users may require
|
|
little more than a few spelling corrections. But to make a US
|
|
application usable by Japanese users, or a Korean application usable
|
|
by German users, will require that the software operate not only in
|
|
different languages, but use different input techniques, character
|
|
encodings and presentation conventions.
|
|
|
|
Qt tries to make internationalization as painless as possible for
|
|
developers. All input widgets and text drawing methods in TQt offer
|
|
built-in support for all supported languages. The built-in font engine
|
|
is capable of correctly and attractively rendering text that contains
|
|
characters from a variety of different writing systems at the same
|
|
time.
|
|
|
|
Qt supports most languages in use today, in particular:
|
|
\list
|
|
\i All East Asian languages (Chinese, Japanese and Korean)
|
|
\i All Western languages (using Latin script)
|
|
\i Arabic
|
|
\i Cyrillic languages (Russian)
|
|
\i Greek
|
|
\i Hebrew
|
|
\i Thai and Lao
|
|
\i All scripts in Unicode 3.2 that do not require special processing
|
|
\endlist
|
|
|
|
On Windows NT/2000/XP and Unix/X11 with Xft (client side font support)
|
|
the following languages are also supported:
|
|
\list
|
|
\i Bengali
|
|
\i Devanagari
|
|
\i Dhivehi (Thaana)
|
|
\i Gujarati
|
|
\i Gurmukhi
|
|
\i Kannada
|
|
\i Khmer
|
|
\i Malayalam (X11 only)
|
|
\i Myanmar (X11 only)
|
|
\i Syriac
|
|
\i Tamil
|
|
\i Telugu
|
|
\i Tibetan (X11 only)
|
|
\endlist
|
|
|
|
Many of these writing systems exhibit special features:
|
|
|
|
\list
|
|
|
|
\i <b>Special line breaking behavior.</b> Some of the Asian languages are
|
|
written without spaces between words. Line breaking can occur either
|
|
after every character (with exceptions) as in Chinese, Japanese and
|
|
Korean, or after logical word boundaries as in Thai.
|
|
|
|
\i <b>Bidirectional writing.</b> Arabic and Hebrew are written from right to
|
|
left, except for numbers and embedded English text which is written
|
|
left to right. The exact behavior is defined in the \link
|
|
http://www.unicode.org/unicode/reports/tr9/ Unicode Technical Report
|
|
#9 \endlink.
|
|
|
|
\i <b>Non spacing or diacritical marks</b> (accents or umlauts in European
|
|
languages). Some languages such as Vietnamese make extensive use of
|
|
these marks and some characters can have more than one mark at the
|
|
same time to clarify pronunciation.
|
|
|
|
\i <b>Ligatures.</b> In special contexts, some pairs of characters get
|
|
replaced by a combined glyph forming a ligature. Common examples are
|
|
the fl and fi ligatures used in typesetting US and European books.
|
|
|
|
\endlist
|
|
|
|
Qt tries to take care of all the special features listed above. You
|
|
usually don't have to worry about these features so long as you use
|
|
Qt's input widgets (e.g. QLineEdit, QTextEdit, and derived classes)
|
|
and Qt's display widgets (e.g. QLabel).
|
|
|
|
Support for these writing systems is transparent to the programmer
|
|
and completely encapsulated in Qt's text engine. This means that you
|
|
don't need to have any knowledge about the writing system used in a
|
|
particular language, except for the following small points:
|
|
\list
|
|
|
|
\i QPainter::drawText( int x, int y, const TQString &str ) will always
|
|
draw the string with it's left edge at the position specified with
|
|
the x, y parameters. This will usually give you left aligned strings.
|
|
Arabic and Hebrew application strings are usually right
|
|
aligned, so for these languages use the version of drawText() that
|
|
takes a QRect since this will align in accordance with the language.
|
|
|
|
\i When you write your own text input controls, use \l
|
|
QFontMetrics::charWidth() to determine the width of a character in a
|
|
string. In some languages (e.g. Arabic or languages from the Indian
|
|
subcontinent), the width and shape of a glyph changes depending on the
|
|
surrounding characters. Writing input controls usually requires a
|
|
certain knowledge of the scripts it is going to be used in. Usually
|
|
the easiest way is to subclass QLineEdit or QTextEdit.
|
|
|
|
\endlist
|
|
|
|
The following sections give some information on the status
|
|
of the internationalization (i18n) support in Qt.
|
|
|
|
See also the \link linguist-manual.book TQt Linguist\endlink manual.
|
|
|
|
\section1 Step by Step
|
|
|
|
Writing multi-platform international software with TQt is a gentle,
|
|
incremental process. Your software can become internationalized in
|
|
the following stages:
|
|
|
|
\section2 Use TQString for all User-visible Text
|
|
|
|
Since TQString uses the Unicode encoding internally, every
|
|
language in the world can be processed transparently using
|
|
familiar text processing operations. Also, since all Qt
|
|
functions that present text to the user take a TQString as a
|
|
parameter, there is no char* to TQString conversion overhead.
|
|
|
|
Strings that are in "programmer space" (such as TQObject names
|
|
and file format texts) need not use TQString; the traditional
|
|
char* or the QCString class will suffice.
|
|
|
|
You're unlikely to notice that you are using Unicode;
|
|
TQString, and TQChar are just like easier versions of the crude
|
|
const char* and char from traditional C.
|
|
|
|
\section2 Use tr() for all Literal Text
|
|
|
|
Wherever your program uses \c{"quoted text"} for text that will
|
|
be presented to the user, ensure that it is processed by the \l
|
|
QApplication::translate() function. Essentially all that is necessary
|
|
to achieve this is to use \l TQObject::tr(). For example, assuming the
|
|
\c LoginWidget is a subclass of TQWidget:
|
|
|
|
\code
|
|
LoginWidget::LoginWidget()
|
|
{
|
|
QLabel *label = new QLabel( tr("Password:"), this );
|
|
...
|
|
}
|
|
\endcode
|
|
|
|
This accounts for 99% of the user-visible strings you're likely to
|
|
write.
|
|
|
|
If the quoted text is not in a member function of a
|
|
TQObject subclass, use either the tr() function of an
|
|
appropriate class, or the QApplication::translate() function
|
|
directly:
|
|
|
|
\code
|
|
void some_global_function( LoginWidget *logwid )
|
|
{
|
|
QLabel *label = new QLabel(
|
|
LoginWidget::tr("Password:"), logwid );
|
|
}
|
|
|
|
void same_global_function( LoginWidget *logwid )
|
|
{
|
|
QLabel *label = new QLabel(
|
|
tqApp->translate("LoginWidget", "Password:"),
|
|
logwid );
|
|
}
|
|
\endcode
|
|
|
|
If you need to have translatable text completely
|
|
outside a function, there are two macros to help: TQT_TR_NOOP()
|
|
and TQT_TRANSLATE_NOOP(). They merely mark the text for
|
|
extraction by the \e lupdate utility described below.
|
|
The macros expand to just the text (without the context).
|
|
|
|
Example of TQT_TR_NOOP():
|
|
\code
|
|
TQString FriendlyConversation::greeting( int greet_type )
|
|
{
|
|
static const char* greeting_strings[] = {
|
|
TQT_TR_NOOP( "Hello" ),
|
|
TQT_TR_NOOP( "Goodbye" )
|
|
};
|
|
return tr( greeting_strings[greet_type] );
|
|
}
|
|
\endcode
|
|
|
|
Example of TQT_TRANSLATE_NOOP():
|
|
\code
|
|
static const char* greeting_strings[] = {
|
|
TQT_TRANSLATE_NOOP( "FriendlyConversation", "Hello" ),
|
|
TQT_TRANSLATE_NOOP( "FriendlyConversation", "Goodbye" )
|
|
};
|
|
|
|
TQString FriendlyConversation::greeting( int greet_type )
|
|
{
|
|
return tr( greeting_strings[greet_type] );
|
|
}
|
|
|
|
TQString global_greeting( int greet_type )
|
|
{
|
|
return tqApp->translate( "FriendlyConversation",
|
|
greeting_strings[greet_type] );
|
|
}
|
|
\endcode
|
|
|
|
If you disable the const char* to TQString automatic conversion
|
|
by compiling your software with the macro TQT_NO_CAST_ASCII
|
|
defined, you'll be very likely to catch any strings you are
|
|
missing. See TQString::fromLatin1() for more information.
|
|
Disabling the conversion can make programming a bit cumbersome.
|
|
|
|
If your source language uses characters outside Latin-1, you
|
|
might find TQObject::trUtf8() more convenient than
|
|
TQObject::tr(), as tr() depends on the
|
|
QApplication::defaultCodec(), which makes it more fragile than
|
|
TQObject::trUtf8().
|
|
|
|
\section2 Use QKeySequence() for Accelerator Values
|
|
|
|
Accelerator values such as Ctrl+Q or Alt+F need to be
|
|
translated too. If you hardcode \c CTRL+Key_Q for "Quit" in
|
|
your application, translators won't be able to override
|
|
it. The correct idiom is
|
|
|
|
\code
|
|
QPopupMenu *file = new QPopupMenu( this );
|
|
file->insertItem( tr("&Quit"), this, TQ_SLOT(quit()),
|
|
QKeySequence(tr("Ctrl+Q", "File|Quit")) );
|
|
\endcode
|
|
|
|
\section2 Use TQString::arg() for Dynamic Text
|
|
|
|
The TQString::arg() functions offer a simple means for substituting
|
|
arguments:
|
|
\code
|
|
void FileCopier::showProgress( int done, int total,
|
|
const TQString& current_file )
|
|
{
|
|
label.setText( tr("%1 of %2 files copied.\nCopying: %3")
|
|
.arg(done)
|
|
.arg(total)
|
|
.arg(current_file) );
|
|
}
|
|
\endcode
|
|
|
|
In some languages the order of arguments may need to change, and this
|
|
can easily be achieved by changing the order of the % arguments. For
|
|
example:
|
|
\code
|
|
TQString s1 = "%1 of %2 files copied. Copying: %3";
|
|
TQString s2 = "Kopierer nu %3. Av totalt %2 filer er %1 kopiert.";
|
|
|
|
tqDebug( s1.arg(5).arg(10).arg("somefile.txt").ascii() );
|
|
tqDebug( s2.arg(5).arg(10).arg("somefile.txt").ascii() );
|
|
\endcode
|
|
|
|
produces the correct output in English and Norwegian:
|
|
\code
|
|
5 of 10 files copied. Copying: somefile.txt
|
|
Kopierer nu somefile.txt. Av totalt 10 filer er 5 kopiert.
|
|
\endcode
|
|
|
|
\section2 Produce Translations
|
|
|
|
Once you are using tr() throughout an application, you can start
|
|
producing translations of the user-visible text in your program.
|
|
|
|
\link linguist-manual.book TQt Linguist\endlink's manual provides
|
|
further information about Qt's translation tools, \e{Qt Linguist}, \e
|
|
lupdate and \e lrelease.
|
|
|
|
Translation of a TQt application is a three-step process:
|
|
|
|
\list 1
|
|
|
|
\i Run \e lupdate to extract translatable text from the C++ source
|
|
code of the TQt application, resulting in a message file for
|
|
translators (a \c .ts file). The utility recognizes the tr() construct
|
|
and the QT_*_NOOP macros described above and produces \c .ts files
|
|
(usually one per language).
|
|
|
|
\i Provide translations for the source texts in the \c .ts file, using
|
|
\e{Qt Linguist}. Since \c .ts files are in XML format, you can also
|
|
edit them by hand.
|
|
|
|
\i Run \e lrelease to obtain a light-weight message file (a \c .qm
|
|
file) from the \c .ts file, suitable only for end use. Think of the \c
|
|
.ts files as "source files", and \c .qm files as "object files". The
|
|
translator edits the \c .ts files, but the users of your application
|
|
only need the \c .qm files. Both kinds of files are platform and
|
|
locale independent.
|
|
|
|
\endlist
|
|
|
|
Typically, you will repeat these steps for every release of your
|
|
application. The \e lupdate utility does its best to reuse the
|
|
translations from previous releases.
|
|
|
|
Before you run \e lupdate, you should prepare a project file. Here's
|
|
an example project file (\c .pro file):
|
|
|
|
\code
|
|
HEADERS = funnydialog.h \
|
|
wackywidget.h
|
|
SOURCES = funnydialog.cpp \
|
|
main.cpp \
|
|
wackywidget.cpp
|
|
FORMS = fancybox.ui
|
|
TRANSLATIONS = superapp_dk.ts \
|
|
superapp_fi.ts \
|
|
superapp_no.ts \
|
|
superapp_se.ts
|
|
\endcode
|
|
|
|
When you run \e lupdate or \e lrelease, you must give the name of the
|
|
project file as a command-line argument.
|
|
|
|
In this example, four exotic languages are supported: Danish, Finnish,
|
|
Norwegian and Swedish. If you use \link qmake-manual.book
|
|
qmake\endlink, you usually don't need an extra project
|
|
file for \e lupdate; your \c qmake project file will work fine once
|
|
you add the \c TRANSLATIONS entry.
|
|
|
|
In your application, you must \l QTranslator::load() the translation
|
|
files appropriate for the user's language, and install them using \l
|
|
QApplication::installTranslator().
|
|
|
|
If you have been using the old TQt tools (\c tqtfindtr, \c msg2tqm and \c
|
|
tqtmergetr), you can use \e tqm2ts to convert your old \c .qm files.
|
|
|
|
\e linguist, \e lupdate and \e lrelease are installed in the \c bin
|
|
subdirectory of the base directory TQt is installed into. Click Help|Manual
|
|
in \e{Qt Linguist} to access the user's manual; it contains a tutorial
|
|
to get you started.
|
|
|
|
While these utilities offer a convenient way to create \c .qm files,
|
|
any system that writes \c .qm files is sufficient. You could make an
|
|
application that adds translations to a QTranslator with
|
|
QTranslator::insert() and then writes a \c .qm file with
|
|
QTranslator::save(). This way the translations can come from any
|
|
source you choose.
|
|
|
|
\target qt-itself
|
|
Qt itself contains over 400 strings that will also need to be
|
|
translated into the languages that you are targeting. You will find
|
|
translation files for French and German in \c $TQTDIR/translations as
|
|
well as a template for translating to other languages. (This directory
|
|
also contains some additional unsupported translations which may be
|
|
useful.)
|
|
|
|
Typically, your application's main() function will look like this:
|
|
\code
|
|
int main( int argc, char **argv )
|
|
{
|
|
QApplication app( argc, argv );
|
|
|
|
// translation file for Qt
|
|
QTranslator qt( 0 );
|
|
qt.load( TQString( "qt_" ) + QTextCodec::locale(), "." );
|
|
app.installTranslator( &qt );
|
|
|
|
// translation file for application strings
|
|
QTranslator myapp( 0 );
|
|
myapp.load( TQString( "myapp_" ) + QTextCodec::locale(), "." );
|
|
app.installTranslator( &myapp );
|
|
|
|
...
|
|
|
|
return app.exec();
|
|
}
|
|
\endcode
|
|
|
|
\section2 Support for Encodings
|
|
|
|
The QTextCodec class and the facilities in QTextStream make it easy to
|
|
support many input and output encodings for your users' data. When an
|
|
application starts, the locale of the machine will determine the 8-bit
|
|
encoding used when dealing with 8-bit data: such as for font
|
|
selection, text display, 8-bit text I/O and character input.
|
|
|
|
The application may occasionally require encodings other than the
|
|
default local 8-bit encoding. For example, an application in a
|
|
Cyrillic KOI8-R locale (the de-facto standard locale in Russia) might
|
|
need to output Cyrillic in the ISO 8859-5 encoding. Code for this
|
|
would be:
|
|
|
|
\code
|
|
TQString string = ...; // some Unicode text
|
|
|
|
QTextCodec* codec = QTextCodec::codecForName( "ISO 8859-5" );
|
|
QCString encoded_string = codec->fromUnicode( string );
|
|
|
|
...; // use encoded_string in 8-bit operations
|
|
\endcode
|
|
|
|
For converting Unicode to local 8-bit encodings, a shortcut is
|
|
available: the \link TQString::local8Bit() local8Bit\endlink() method
|
|
of TQString returns such 8-bit data. Another useful shortcut is the
|
|
\link TQString::utf8() utf8\endlink() method, which returns text in the
|
|
8-bit UTF-8 encoding: this perfectly preserves Unicode information
|
|
while looking like plain US-ASCII if the text is wholly US-ASCII.
|
|
|
|
For converting the other way, there are the TQString::fromUtf8() and
|
|
TQString::fromLocal8Bit() convenience functions, or the general code,
|
|
demonstrated by this conversion from ISO 8859-5 Cyrillic to Unicode
|
|
conversion:
|
|
|
|
\code
|
|
QCString encoded_string = ...; // Some ISO 8859-5 encoded text.
|
|
|
|
QTextCodec* codec = QTextCodec::codecForName("ISO 8859-5");
|
|
TQString string = codec->toUnicode(encoded_string);
|
|
|
|
...; // Use string in all of Qt's TQString operations.
|
|
\endcode
|
|
|
|
Ideally Unicode I/O should be used as this maximizes the portability
|
|
of documents between users around the world, but in reality it is
|
|
useful to support all the appropriate encodings that your users will
|
|
need to process existing documents. In general, Unicode (UTF-16 or
|
|
UTF-8) is best for information transferred between arbitrary people,
|
|
while within a language or national group, a local standard is often
|
|
more appropriate. The most important encoding to support is the one
|
|
returned by QTextCodec::codecForLocale(), as this is the one the user
|
|
is most likely to need for communicating with other people and
|
|
applications (this is the codec used by local8Bit()).
|
|
|
|
Qt supports most of the more frequently used encodings natively. For a
|
|
complete list of supported encodings see the \l QTextCodec
|
|
documentation.
|
|
|
|
In some cases and for less frequently used encodings it may be
|
|
necessary to write your own QTextCodec subclass. Depending on the
|
|
urgency, it may be useful to contact Trolltech technical support or
|
|
ask on the \c qt-interest mailing list to see if someone else is
|
|
already working on supporting the encoding. A useful interim measure
|
|
can be to use the QTextCodec::loadCharmapFile() function to build a
|
|
data-driven codec, although this approach has a memory and speed
|
|
penalty, especially with dynamically loaded libraries. For details of
|
|
writing your own QTextCodec, see the main QTextCodec class
|
|
documentation.
|
|
|
|
\keyword localization
|
|
|
|
\section2 Localize
|
|
|
|
Localization is the process of adapting to local conventions, for
|
|
example presenting dates and times using the locally preferred
|
|
formats. Such localizations can be accomplished using appropriate tr()
|
|
strings.
|
|
|
|
\code
|
|
void Clock::setTime(const QTime& t)
|
|
{
|
|
if ( tr("AMPM") == "AMPM" ) {
|
|
// 12-hour clock
|
|
} else {
|
|
// 24-hour clock
|
|
}
|
|
}
|
|
\endcode
|
|
|
|
In the example, for the US we would leave the translation of "AMPM" as
|
|
it is and thereby use the 12-hour clock branch; but in Europe we would
|
|
translate it as something else (anything else, e.g. "EU") and this
|
|
will make the code use the 24-hour clock branch.
|
|
|
|
Localizing images is not recommended. Choose clear icons that are
|
|
appropriate for all localities, rather than relying on local puns or
|
|
stretched metaphors.
|
|
|
|
\section1 Dynamic Translation
|
|
|
|
Some applications, such as TQt Linguist, must be able to support changes
|
|
to the user's language settings while they are still running. To make
|
|
widgets aware of changes to the system language, implement a public
|
|
slot called \c languageChange() in each widget that needs to be notified.
|
|
In this slot, you should update the text displayed by widgets using the
|
|
\l{TQObject::tr()}{tr()} function in the usual way; for example:
|
|
|
|
\code
|
|
void MyWidget::languageChange()
|
|
{
|
|
titleLabel->setText(tr("Document Title"));
|
|
...
|
|
okPushButton->setText(tr("&OK"));
|
|
}
|
|
\endcode
|
|
|
|
The default event handler for TQWidget subclasses responds to the
|
|
\link QEvent::Type LanguageChange\endlink event, and will call this slot
|
|
when necessary; other application components can also connect signals
|
|
to this slot to force widgets to update themselves.
|
|
|
|
\section1 System Support
|
|
|
|
Some of the operating systems and windowing systems that TQt runs on
|
|
only have limited support for Unicode. The level of support available
|
|
in the underlying system has some influence on the support that TQt can
|
|
provide on those platforms, although in general TQt applications need
|
|
not be too concerned with platform-specific limitations.
|
|
|
|
\section2 Unix/X11
|
|
|
|
\list
|
|
\i Locale-oriented fonts and input methods. TQt hides these and
|
|
provides Unicode input and output.
|
|
\i Filesystem conventions such as
|
|
\link http://www.ietf.org/rfc/rfc2279.txt UTF-8 \endlink
|
|
are under development
|
|
in some Unix variants. All TQt file functions allow Unicode,
|
|
but convert filenames to the local 8-bit encoding, as
|
|
this is the Unix convention
|
|
(see QFile::setEncodingFunction()
|
|
to explore alternative encodings).
|
|
\i File I/O defaults to the local 8-bit encoding,
|
|
with Unicode options in QTextStream.
|
|
\endlist
|
|
|
|
\section2 Windows
|
|
|
|
\list
|
|
\i TQt provides full Unicode support, including input methods, fonts,
|
|
clipboard, drag-and-drop and file names.
|
|
\i File I/O defaults to Latin-1, with Unicode options in QTextStream.
|
|
Note that some Windows programs do not understand big-endian
|
|
Unicode text files even though that is the order prescribed by
|
|
the Unicode Standard in the absence of higher-level protocols.
|
|
\i Unlike programs written with MFC or plain winlib, TQt programs
|
|
are portable between Windows 95/98 and Windows NT.
|
|
\e {You do not need different binaries to support Unicode.}
|
|
\endlist
|
|
|
|
\section1 Note about Locales on X11
|
|
|
|
Many Unix distributions contain only partial support for some locales.
|
|
For example, if you have a \c /usr/share/locale/ja_JP.EUC directory,
|
|
this does not necessarily mean you can display Japanese text; you also
|
|
need JIS encoded fonts (or Unicode fonts), and the \c
|
|
/usr/share/locale/ja_JP.EUC directory needs to be complete. For best
|
|
results, use complete locales from your system vendor.
|
|
|
|
\section1 Relevant TQt Classes
|
|
|
|
These classes are relevant to internationalizing TQt applications.
|
|
*/
|