mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-08 23:10:40 +00:00
parent
faa2f9f9e1
commit
46ec4fd523
7 changed files with 304 additions and 54 deletions
|
@ -80,7 +80,6 @@ UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedList)
|
|||
|
||||
|
||||
static Hashtable* listPatternHash = nullptr;
|
||||
static const char STANDARD_STYLE[] = "standard";
|
||||
|
||||
U_CDECL_BEGIN
|
||||
static UBool U_CALLCONV uprv_listformatter_cleanup() {
|
||||
|
@ -179,6 +178,50 @@ const ListFormatInternal* ListFormatter::getListFormatInternal(
|
|||
return result;
|
||||
}
|
||||
|
||||
static const char* typeWidthToStyleString(UListFormatterType type, UListFormatterWidth width) {
|
||||
switch (type) {
|
||||
case ULISTFMT_TYPE_AND:
|
||||
switch (width) {
|
||||
case ULISTFMT_WIDTH_WIDE:
|
||||
return "standard";
|
||||
case ULISTFMT_WIDTH_SHORT:
|
||||
return "standard-short";
|
||||
case ULISTFMT_WIDTH_NARROW:
|
||||
return "standard-narrow";
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
|
||||
case ULISTFMT_TYPE_OR:
|
||||
switch (width) {
|
||||
case ULISTFMT_WIDTH_WIDE:
|
||||
return "or";
|
||||
case ULISTFMT_WIDTH_SHORT:
|
||||
return "or-short";
|
||||
case ULISTFMT_WIDTH_NARROW:
|
||||
return "or-narrow";
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
|
||||
case ULISTFMT_TYPE_UNITS:
|
||||
switch (width) {
|
||||
case ULISTFMT_WIDTH_WIDE:
|
||||
return "unit";
|
||||
case ULISTFMT_WIDTH_SHORT:
|
||||
return "unit-short";
|
||||
case ULISTFMT_WIDTH_NARROW:
|
||||
return "unit-narrow";
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const UChar solidus = 0x2F;
|
||||
static const UChar aliasPrefix[] = { 0x6C,0x69,0x73,0x74,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x2F }; // "listPattern/"
|
||||
enum {
|
||||
|
@ -297,7 +340,17 @@ ListFormatter* ListFormatter::createInstance(UErrorCode& errorCode) {
|
|||
}
|
||||
|
||||
ListFormatter* ListFormatter::createInstance(const Locale& locale, UErrorCode& errorCode) {
|
||||
return createInstance(locale, STANDARD_STYLE, errorCode);
|
||||
return createInstance(locale, ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_WIDE, errorCode);
|
||||
}
|
||||
|
||||
ListFormatter* ListFormatter::createInstance(
|
||||
const Locale& locale, UListFormatterType type, UListFormatterWidth width, UErrorCode& errorCode) {
|
||||
const char* style = typeWidthToStyleString(type, width);
|
||||
if (style == nullptr) {
|
||||
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return nullptr;
|
||||
}
|
||||
return createInstance(locale, style, errorCode);
|
||||
}
|
||||
|
||||
ListFormatter* ListFormatter::createInstance(const Locale& locale, const char *style, UErrorCode& errorCode) {
|
||||
|
|
|
@ -34,6 +34,21 @@ ulistfmt_open(const char* locale,
|
|||
}
|
||||
|
||||
|
||||
U_CAPI UListFormatter* U_EXPORT2
|
||||
ulistfmt_openForType(const char* locale, UListFormatterType type,
|
||||
UListFormatterWidth width, UErrorCode* status)
|
||||
{
|
||||
if (U_FAILURE(*status)) {
|
||||
return NULL;
|
||||
}
|
||||
LocalPointer<ListFormatter> listfmt(ListFormatter::createInstance(Locale(locale), type, width, *status));
|
||||
if (U_FAILURE(*status)) {
|
||||
return NULL;
|
||||
}
|
||||
return (UListFormatter*)listfmt.orphan();
|
||||
}
|
||||
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
ulistfmt_close(UListFormatter *listfmt)
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "unicode/unistr.h"
|
||||
#include "unicode/locid.h"
|
||||
#include "unicode/formattedvalue.h"
|
||||
#include "unicode/ulistformatter.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -185,10 +186,27 @@ class U_I18N_API ListFormatter : public UObject{
|
|||
*/
|
||||
static ListFormatter* createInstance(const Locale& locale, UErrorCode& errorCode);
|
||||
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
/**
|
||||
* Creates a ListFormatter for the given locale, list type, and style.
|
||||
*
|
||||
* @param locale The locale.
|
||||
* @param type The type of list formatting to use.
|
||||
* @param width The width of formatting to use.
|
||||
* @param errorCode ICU error code, set if no data available for the given locale.
|
||||
* @return A ListFormatter object created from internal data derived from CLDR data.
|
||||
* @draft ICU 67
|
||||
*/
|
||||
static ListFormatter* createInstance(
|
||||
const Locale& locale, UListFormatterType type, UListFormatterWidth width, UErrorCode& errorCode);
|
||||
#endif /* U_HIDE_DRAFT_API */
|
||||
|
||||
#ifndef U_HIDE_INTERNAL_API
|
||||
/**
|
||||
* Creates a ListFormatter appropriate for a locale and style.
|
||||
*
|
||||
* TODO(ICU-20888): Remove this in ICU 68.
|
||||
*
|
||||
* @param locale The locale.
|
||||
* @param style the style, either "standard", "or", "unit", "unit-narrow", or "unit-short"
|
||||
* @param errorCode ICU error code, set if no data available for the given locale.
|
||||
|
|
|
@ -61,10 +61,67 @@ typedef enum UListFormatterField {
|
|||
*/
|
||||
ULISTFMT_ELEMENT_FIELD
|
||||
} UListFormatterField;
|
||||
|
||||
/**
|
||||
* Type of meaning expressed by the list.
|
||||
*
|
||||
* @draft ICU 67
|
||||
*/
|
||||
typedef enum UListFormatterType {
|
||||
/**
|
||||
* Conjunction formatting, e.g. "Alice, Bob, Charlie, and Delta".
|
||||
*
|
||||
* @draft ICU 67
|
||||
*/
|
||||
ULISTFMT_TYPE_AND,
|
||||
|
||||
/**
|
||||
* Disjunction (or alternative, or simply one of) formatting, e.g.
|
||||
* "Alice, Bob, Charlie, or Delta".
|
||||
*
|
||||
* @draft ICU 67
|
||||
*/
|
||||
ULISTFMT_TYPE_OR,
|
||||
|
||||
/**
|
||||
* Formatting of a list of values with units, e.g. "5 pounds, 12 ounces".
|
||||
*
|
||||
* @draft ICU 67
|
||||
*/
|
||||
ULISTFMT_TYPE_UNITS
|
||||
} UListFormatterType;
|
||||
|
||||
/**
|
||||
* Verbosity level of the list patterns.
|
||||
*
|
||||
* @draft ICU 67
|
||||
*/
|
||||
typedef enum UListFormatterWidth {
|
||||
/**
|
||||
* Use list formatting with full words (no abbreviations) when possible.
|
||||
*
|
||||
* @draft ICU 67
|
||||
*/
|
||||
ULISTFMT_WIDTH_WIDE,
|
||||
|
||||
/**
|
||||
* Use list formatting of typical length.
|
||||
* @draft ICU 67
|
||||
*/
|
||||
ULISTFMT_WIDTH_SHORT,
|
||||
|
||||
/**
|
||||
* Use list formatting of the shortest possible length.
|
||||
* @draft ICU 67
|
||||
*/
|
||||
ULISTFMT_WIDTH_NARROW,
|
||||
} UListFormatterWidth;
|
||||
#endif /* U_HIDE_DRAFT_API */
|
||||
|
||||
/**
|
||||
* Open a new UListFormatter object using the rules for a given locale.
|
||||
* The object will be initialized with AND type and WIDE width.
|
||||
*
|
||||
* @param locale
|
||||
* The locale whose rules should be used; may be NULL for
|
||||
* default locale.
|
||||
|
@ -83,6 +140,34 @@ U_CAPI UListFormatter* U_EXPORT2
|
|||
ulistfmt_open(const char* locale,
|
||||
UErrorCode* status);
|
||||
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
/**
|
||||
* Open a new UListFormatter object appropriate for the given locale, list type,
|
||||
* and style.
|
||||
*
|
||||
* @param locale
|
||||
* The locale whose rules should be used; may be NULL for
|
||||
* default locale.
|
||||
* @param type
|
||||
* The type of list formatting to use.
|
||||
* @param width
|
||||
* The width of formatting to use.
|
||||
* @param status
|
||||
* A pointer to a standard ICU UErrorCode (input/output parameter).
|
||||
* Its input value must pass the U_SUCCESS() test, or else the
|
||||
* function returns immediately. The caller should check its output
|
||||
* value with U_FAILURE(), or use with function chaining (see User
|
||||
* Guide for details).
|
||||
* @return
|
||||
* A pointer to a UListFormatter object for the specified locale,
|
||||
* or NULL if an error occurred.
|
||||
* @draft ICU 67
|
||||
*/
|
||||
U_CAPI UListFormatter* U_EXPORT2
|
||||
ulistfmt_openForType(const char* locale, UListFormatterType type,
|
||||
UListFormatterWidth width, UErrorCode* status);
|
||||
#endif /* U_HIDE_DRAFT_API */
|
||||
|
||||
/**
|
||||
* Close a UListFormatter object. Once closed it may no longer be used.
|
||||
* @param listfmt
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
static void TestUListFmt(void);
|
||||
static void TestUListFmtToValue(void);
|
||||
static void TestUListOpenStyled(void);
|
||||
|
||||
void addUListFmtTest(TestNode** root);
|
||||
|
||||
|
@ -28,6 +29,7 @@ void addUListFmtTest(TestNode** root)
|
|||
{
|
||||
TESTCASE(TestUListFmt);
|
||||
TESTCASE(TestUListFmtToValue);
|
||||
TESTCASE(TestUListOpenStyled);
|
||||
}
|
||||
|
||||
static const UChar str0[] = { 0x41,0 }; /* "A" */
|
||||
|
@ -210,5 +212,43 @@ static void TestUListFmtToValue() {
|
|||
ulistfmt_closeResult(fl);
|
||||
}
|
||||
|
||||
static void TestUListOpenStyled() {
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
UListFormatter* fmt = ulistfmt_openForType("en", ULISTFMT_TYPE_OR, ULISTFMT_WIDTH_SHORT, &ec);
|
||||
UFormattedList* fl = ulistfmt_openResult(&ec);
|
||||
assertSuccess("Opening", &ec);
|
||||
|
||||
{
|
||||
const char* message = "openStyled test 1";
|
||||
const UChar* expectedString = u"A, B, or C";
|
||||
const UChar* inputs[] = {
|
||||
u"A",
|
||||
u"B",
|
||||
u"C",
|
||||
};
|
||||
ulistfmt_formatStringsToResult(fmt, inputs, NULL, UPRV_LENGTHOF(inputs), fl, &ec);
|
||||
assertSuccess("Formatting", &ec);
|
||||
static const UFieldPositionWithCategory expectedFieldPositions[] = {
|
||||
// field, begin index, end index
|
||||
{UFIELD_CATEGORY_LIST_SPAN, 0, 0, 1},
|
||||
{UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 0, 1},
|
||||
{UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 1, 3},
|
||||
{UFIELD_CATEGORY_LIST_SPAN, 1, 3, 4},
|
||||
{UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 3, 4},
|
||||
{UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 4, 9},
|
||||
{UFIELD_CATEGORY_LIST_SPAN, 2, 9, 10},
|
||||
{UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 9, 10}};
|
||||
checkMixedFormattedValue(
|
||||
message,
|
||||
ulistfmt_resultAsValue(fl, &ec),
|
||||
expectedString,
|
||||
expectedFieldPositions,
|
||||
UPRV_LENGTHOF(expectedFieldPositions));
|
||||
}
|
||||
|
||||
ulistfmt_close(fmt);
|
||||
ulistfmt_closeResult(fl);
|
||||
}
|
||||
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
|
@ -23,6 +23,37 @@
|
|||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
void ListFormatterTest::runIndexedTest(int32_t index, UBool exec,
|
||||
const char* &name, char* /*par */) {
|
||||
TESTCASE_AUTO_BEGIN;
|
||||
TESTCASE_AUTO(TestRoot);
|
||||
TESTCASE_AUTO(TestBogus);
|
||||
TESTCASE_AUTO(TestEnglish);
|
||||
TESTCASE_AUTO(TestEnglishUS);
|
||||
TESTCASE_AUTO(TestRussian);
|
||||
TESTCASE_AUTO(TestMalayalam);
|
||||
TESTCASE_AUTO(TestZulu);
|
||||
TESTCASE_AUTO(TestOutOfOrderPatterns);
|
||||
TESTCASE_AUTO(Test9946);
|
||||
TESTCASE_AUTO(TestEnglishGB);
|
||||
TESTCASE_AUTO(TestNynorsk);
|
||||
TESTCASE_AUTO(TestChineseTradHK);
|
||||
TESTCASE_AUTO(TestFieldPositionIteratorWontCrash);
|
||||
TESTCASE_AUTO(TestFieldPositionIteratorWith1Item);
|
||||
TESTCASE_AUTO(TestFieldPositionIteratorWith1ItemAndDataBefore);
|
||||
TESTCASE_AUTO(TestFieldPositionIteratorWith2Items);
|
||||
TESTCASE_AUTO(TestFieldPositionIteratorWith2ItemsAndDataBefore);
|
||||
TESTCASE_AUTO(TestFieldPositionIteratorWith2ItemsPatternShift);
|
||||
TESTCASE_AUTO(TestFieldPositionIteratorWith3Items);
|
||||
TESTCASE_AUTO(TestFieldPositionIteratorWith3ItemsAndDataBefore);
|
||||
TESTCASE_AUTO(TestFieldPositionIteratorWith3ItemsPatternShift);
|
||||
TESTCASE_AUTO(TestFormattedValue);
|
||||
TESTCASE_AUTO(TestDifferentStyles);
|
||||
TESTCASE_AUTO(TestBadStylesFail);
|
||||
TESTCASE_AUTO(TestCreateStyled);
|
||||
TESTCASE_AUTO_END;
|
||||
}
|
||||
|
||||
namespace {
|
||||
const char* attrString(int32_t attrId) {
|
||||
switch (attrId) {
|
||||
|
@ -611,58 +642,65 @@ void ListFormatterTest::TestBadStylesFail() {
|
|||
}
|
||||
}
|
||||
|
||||
void ListFormatterTest::runIndexedTest(int32_t index, UBool exec,
|
||||
const char* &name, char* /*par */) {
|
||||
switch(index) {
|
||||
case 0: name = "TestRoot"; if (exec) TestRoot(); break;
|
||||
case 1: name = "TestBogus"; if (exec) TestBogus(); break;
|
||||
case 2: name = "TestEnglish"; if (exec) TestEnglish(); break;
|
||||
case 3: name = "TestEnglishUS"; if (exec) TestEnglishUS(); break;
|
||||
case 4: name = "TestRussian"; if (exec) TestRussian(); break;
|
||||
case 5: name = "TestMalayalam"; if (exec) TestMalayalam(); break;
|
||||
case 6: name = "TestZulu"; if (exec) TestZulu(); break;
|
||||
case 7: name = "TestOutOfOrderPatterns"; if (exec) TestOutOfOrderPatterns(); break;
|
||||
case 8: name = "Test9946"; if (exec) Test9946(); break;
|
||||
case 9: name = "TestEnglishGB"; if (exec) TestEnglishGB(); break;
|
||||
case 10: name = "TestNynorsk"; if (exec) TestNynorsk(); break;
|
||||
case 11: name = "TestChineseTradHK"; if (exec) TestChineseTradHK(); break;
|
||||
case 12: name = "TestFieldPositionIteratorWontCrash";
|
||||
if (exec) TestFieldPositionIteratorWontCrash();
|
||||
break;
|
||||
case 13: name = "TestFieldPositionIteratorWith1Item";
|
||||
if (exec) TestFieldPositionIteratorWith1Item();
|
||||
break;
|
||||
case 14: name = "TestFieldPositionIteratorWith1ItemAndDataBefore";
|
||||
if (exec) TestFieldPositionIteratorWith1ItemAndDataBefore();
|
||||
break;
|
||||
case 15: name = "TestFieldPositionIteratorWith2Items";
|
||||
if (exec) TestFieldPositionIteratorWith2Items();
|
||||
break;
|
||||
case 16: name = "TestFieldPositionIteratorWith2ItemsAndDataBefore";
|
||||
if (exec) TestFieldPositionIteratorWith2ItemsAndDataBefore();
|
||||
break;
|
||||
case 17: name = "TestFieldPositionIteratorWith2ItemsPatternShift";
|
||||
if (exec) TestFieldPositionIteratorWith2ItemsPatternShift();
|
||||
break;
|
||||
case 18: name = "TestFieldPositionIteratorWith3Items";
|
||||
if (exec) TestFieldPositionIteratorWith3Items();
|
||||
break;
|
||||
case 19: name = "TestFieldPositionIteratorWith3ItemsAndDataBefore";
|
||||
if (exec) TestFieldPositionIteratorWith3ItemsAndDataBefore();
|
||||
break;
|
||||
case 20: name = "TestFieldPositionIteratorWith3ItemsPatternShift";
|
||||
if (exec) TestFieldPositionIteratorWith3ItemsPatternShift();
|
||||
break;
|
||||
case 21: name = "TestFormattedValue";
|
||||
if (exec) TestFormattedValue();
|
||||
break;
|
||||
case 22: name = "TestDifferentStyles";
|
||||
if (exec) TestDifferentStyles();
|
||||
break;
|
||||
case 23: name = "TestBadStylesFail";
|
||||
if (exec) TestBadStylesFail();
|
||||
break;
|
||||
default: name = ""; break;
|
||||
void ListFormatterTest::TestCreateStyled() {
|
||||
IcuTestErrorCode status(*this, "TestCreateStyled");
|
||||
// Locale en has interesting data
|
||||
struct TestCase {
|
||||
const char* locale;
|
||||
UListFormatterType type;
|
||||
UListFormatterWidth width;
|
||||
const char16_t* expected3;
|
||||
const char16_t* expected2;
|
||||
const char16_t* expected1;
|
||||
} cases[] = {
|
||||
{ "pt", ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_WIDE, u"A, B e C", u"A e B", u"A" },
|
||||
{ "pt", ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_SHORT, u"A, B e C", u"A e B", u"A" },
|
||||
{ "pt", ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_NARROW, u"A, B, C", u"A, B", u"A" },
|
||||
{ "pt", ULISTFMT_TYPE_OR, ULISTFMT_WIDTH_WIDE, u"A, B ou C", u"A ou B", u"A" },
|
||||
{ "pt", ULISTFMT_TYPE_OR, ULISTFMT_WIDTH_SHORT, u"A, B ou C", u"A ou B", u"A" },
|
||||
{ "pt", ULISTFMT_TYPE_OR, ULISTFMT_WIDTH_NARROW, u"A, B ou C", u"A ou B", u"A" },
|
||||
{ "pt", ULISTFMT_TYPE_UNITS, ULISTFMT_WIDTH_WIDE, u"A, B e C", u"A e B", u"A" },
|
||||
{ "pt", ULISTFMT_TYPE_UNITS, ULISTFMT_WIDTH_SHORT, u"A, B e C", u"A e B", u"A" },
|
||||
{ "pt", ULISTFMT_TYPE_UNITS, ULISTFMT_WIDTH_NARROW, u"A B C", u"A B", u"A" },
|
||||
{ "en", ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_WIDE, u"A, B, and C", u"A and B", u"A" },
|
||||
{ "en", ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_SHORT, u"A, B, & C", u"A & B", u"A" },
|
||||
{ "en", ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_NARROW, u"A, B, C", u"A, B", u"A" },
|
||||
{ "en", ULISTFMT_TYPE_OR, ULISTFMT_WIDTH_WIDE, u"A, B, or C", u"A or B", u"A" },
|
||||
{ "en", ULISTFMT_TYPE_OR, ULISTFMT_WIDTH_SHORT, u"A, B, or C", u"A or B", u"A" },
|
||||
{ "en", ULISTFMT_TYPE_OR, ULISTFMT_WIDTH_NARROW, u"A, B, or C", u"A or B", u"A" },
|
||||
{ "en", ULISTFMT_TYPE_UNITS, ULISTFMT_WIDTH_WIDE, u"A, B, C", u"A, B", u"A" },
|
||||
{ "en", ULISTFMT_TYPE_UNITS, ULISTFMT_WIDTH_SHORT, u"A, B, C", u"A, B", u"A" },
|
||||
{ "en", ULISTFMT_TYPE_UNITS, ULISTFMT_WIDTH_NARROW, u"A B C", u"A B", u"A" },
|
||||
};
|
||||
for (auto cas : cases) {
|
||||
LocalPointer<ListFormatter> fmt(
|
||||
ListFormatter::createInstance(cas.locale, cas.type, cas.width, status),
|
||||
status);
|
||||
if (status.errIfFailureAndReset()) {
|
||||
continue;
|
||||
}
|
||||
UnicodeString message = UnicodeString(u"TestCreateStyled loc=")
|
||||
+ cas.locale + u" type="
|
||||
+ Int64ToUnicodeString(cas.type) + u" width="
|
||||
+ Int64ToUnicodeString(cas.width);
|
||||
const UnicodeString inputs3[] = {
|
||||
u"A",
|
||||
u"B",
|
||||
u"C"
|
||||
};
|
||||
FormattedList result = fmt->formatStringsToValue(inputs3, UPRV_LENGTHOF(inputs3), status);
|
||||
assertEquals(message, cas.expected3, result.toTempString(status));
|
||||
const UnicodeString inputs2[] = {
|
||||
u"A",
|
||||
u"B"
|
||||
};
|
||||
result = fmt->formatStringsToValue(inputs2, UPRV_LENGTHOF(inputs2), status);
|
||||
assertEquals(message, cas.expected2, result.toTempString(status));
|
||||
const UnicodeString inputs1[] = {
|
||||
u"A"
|
||||
};
|
||||
result = fmt->formatStringsToValue(inputs1, UPRV_LENGTHOF(inputs1), status);
|
||||
assertEquals(message, cas.expected1, result.toTempString(status));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ class ListFormatterTest : public IntlTestWithFieldPosition {
|
|||
void TestFormattedValue();
|
||||
void TestDifferentStyles();
|
||||
void TestBadStylesFail();
|
||||
void TestCreateStyled();
|
||||
|
||||
private:
|
||||
void CheckFormatting(
|
||||
|
|
Loading…
Add table
Reference in a new issue