1--- 2layout: default 3title: Message Formatting Examples 4nav_order: 1 5parent: Formatting Messages 6grand_parent: Formatting 7--- 8<!-- 9© 2020 and later: Unicode, Inc. and others. 10License & terms of use: http://www.unicode.org/copyright.html 11--> 12 13# Message Formatting Examples 14{: .no_toc } 15 16## Contents 17{: .no_toc .text-delta } 18 191. TOC 20{:toc} 21 22--- 23 24## `MessageFormat` Class 25 26ICU's `MessageFormat` class can be used to format messages in a locale-independent 27manner to localize the user interface (UI) strings. 28 29### C++ 30 31```cpp 32 33/* The strings below can be isolated into a resource bundle 34* and retrieved dynamically 35*/ 36#define LANGUAGE_NAMES "{0}<{1}languages {2}>\n" 37#define LANG_ATTRIB "{0}<language id=\"{1}\" >{2}</language>\n" 38#define MONTH_NAMES "{0}<monthNames>\n" 39#define END_MONTH_NAMES "{0}</monthNames>\n" 40#define MONTH "{0}<month id=\"{1}\">{2}</month>\n" 41#define MONTH_ABBR "{0}<monthAbbr>\n" 42#define END_MONTH_ABBR "{0}</monthAbbr>\n" 43 44UnicodeString CXMLGenerator::formatString(UnicodeString& str,UnicodeString& 45argument){ 46Formattable args[] ={ argument}; 47UnicodeString result; 48MessageFormat format(str,mError); 49FieldPosition fpos=0; 50format.format(args,1, result,fpos,mError); 51if(U_FAILURE(mError)) { 52 return UnicodeString("Illegal argument"); 53} 54 55return result; 56} 57 58void CXMLGenerator::writeLanguage(UnicodeString& xmlString){ 59 60UnicodeString *itemTags, *items; 61char* key="Languages"; 62int32_t numItems; 63 64if(U_FAILURE(mError)) { 65 return; 66} 67 68mRBundle.getTaggedArray(key,itemTags, items, numItems, mError); 69if(mError!=U_USING_DEFAULT_ERROR && U_SUCCESS(mError) && 70mError!=U_ERROR_INFO_START){ 71 72 Formattable args[]={indentOffset,"",""}; 73 xmlString= formatString(UnicodeString(LANGUAGE_NAMES),args,3); 74 indentOffset.append("\t"); 75 for(int32_t i=0;i<numItems;i++){ 76 77 args[0] = indentOffset; 78 args[1] =itemTags[i] ; 79 args[2] = items[i] ; 80 xmlString.append(formatString(UnicodeString(LANG_ATTRIB),args,3)); 81 } 82 83 chopIndent(); 84 args[0]=indentOffset; 85 args[1] =(UnicodeString(XML_END_SLASH)); 86 args[2] = ""; 87 xmlString.append(formatString(UnicodeString(LANGUAGE_NAMES),args,3)); 88 89 return; 90} 91mError=U_ZERO_ERROR; 92xmlString.remove(); 93} 94 95 96void CXMLGenerator::writeMonthNames(UnicodeString& xmlString){ 97 98int32_t lNum; 99const UnicodeString* longMonths= 100mRBundle.getStringArray("MonthNames",lNum,mError); 101if(mError!=U_USING_DEFAULT_ERROR && mError!=U_ERROR_INFO_START && mError != 102U_MISSING_RESOURCE_ERROR){ 103 xmlString.append(formatString(UnicodeString(MONTH_NAMES),indentOffset)); 104 indentOffset.append("\t"); 105 for(int i=0;i<lNum;i++){ 106 char c; 107 itoa(i+1,&c,10); 108 Formattable args[]={indentOffset,UnicodeString(&c),longMonths[i]}; 109 xmlString.append(formatString(UnicodeString(MONTH),args,3)); 110 } 111 chopIndent(); 112 xmlString.append(formatString(UnicodeString(END_MONTH_NAMES),indentOffset)); 113 mError=U_ZERO_ERROR; 114 return; 115} 116xmlString.remove(); 117mError= U_ZERO_ERROR; 118} 119``` 120 121### C 122 123```c 124 125void msgSample1(){ 126 127 UChar *result, *tzID, *str; 128 UChar pattern[100]; 129 int32_t resultLengthOut, resultlength; 130 UCalendar *cal; 131 UDate d1; 132 UErrorCode status = U_ZERO_ERROR; 133 str=(UChar*)malloc(sizeof(UChar) * (strlen("disturbance in force") +1)); 134 u_uastrcpy(str, "disturbance in force"); 135 tzID=(UChar*)malloc(sizeof(UChar) * 4); 136 u_uastrcpy(tzID, "PST"); 137 cal=ucal_open(tzID, u_strlen(tzID), "en_US", UCAL_TRADITIONAL, &status); 138 ucal_setDateTime(cal, 1999, UCAL_MARCH, 18, 0, 0, 0, &status); 139 d1=ucal_getMillis(cal, &status); 140 u_uastrcpy(pattern, "On {0, date, long}, there was a {1} on planet 141{2,number,integer}"); 142 resultlength=0; 143 resultLengthOut=u_formatMessage( "en_US", pattern, u_strlen(pattern), 144NULL, 145resultlength, &status, d1, str, 7); 146 if(status==U_BUFFER_OVERFLOW_ERROR){ 147 status=U_ZERO_ERROR; 148 resultlength=resultLengthOut+1; 149 result=(UChar*)realloc(result, sizeof(UChar) * resultlength); 150 u_formatMessage( "en_US", pattern, u_strlen(pattern), result, 151resultlength, &status, d1, str, 7); 152 } 153 printf("%s\n",austrdup(result) ); //austrdup( a function used to convert 154UChar* to char*) 155 free(tzID); 156 free(str); 157 free(result); 158} 159 160char *austrdup(const UChar* unichars) 161 162{ 163 int length; 164 char *newString; 165 166 length = u_strlen ( unichars ); 167 newString = (char*)malloc ( sizeof( char ) * 4 * ( length + 1 ) ); 168 if ( newString == NULL ) 169 return NULL; 170 171 u_austrcpy ( newString, unichars ); 172 173 return newString; 174} 175 176This is a more practical sample which retrieves data from a resource bundle 177and 178feeds the data 179to u_formatMessage to produce a formatted string 180 181void msgSample3(){ 182 183char* key="Languages"; 184int32_t numItems; 185 /* This constant string can also be in the resouce bundle and retrieved at 186the time 187 * of formatting 188 * eg: 189 * UResouceBundle* myResB = ures_open("myResources",currentLocale,&err); 190 * UChar* Lang_Attrib = ures_getString(myResb,"LANG_ATTRIB",&err); 191 */ 192 UChar* LANG_ATTRIB =(UChar*) "{0}<language id=\"{1}\" 193>{2}</language>\n"; 194 UChar *result; 195 UResourceBundle* pResB,*pDeltaResB=NULL; 196 UErrorCode err=U_ZERO_ERROR; 197 UChar* indentOffset = (UChar*)"\t\t\t"; 198 pResB = ures_open("","en",&err); 199if(U_FAILURE(err)) { 200 return; 201} 202 203 ures_getByKey(pResB, key, pDeltaResB, &err); 204 205 if(U_SUCCESS(err)) { 206 const UChar *value = 0; 207 const char *key = 0; 208 int32_t len = 0; 209 int16_t indexR = -1; 210 int32_t resultLength=0,resultLengthOut=0; 211 numItems = ures_getSize(pDeltaResB); 212 for(;numItems-->0;){ 213 key= ures_getKey(pDeltaResB); 214 value = ures_get(pDeltaResB,key,&err); 215 resultLength=0; 216 resultLengthOut=u_formatMessage( "en_US", LANG_ATTRIB, 217u_strlen(LANG_ATTRIB), 218 NULL, resultLength, &err, 219indentOffset, value, key); 220 if(err==U_BUFFER_OVERFLOW_ERROR){ 221 err=U_ZERO_ERROR; 222 resultLength=resultLengthOut+1; 223 result=(UChar*)realloc(result, sizeof(UChar) * resultLength); 224 u_formatMessage("en_US",LANG_ATTRIB,u_strlen(LANG_ATTRIB), 225 result,resultLength,&err,indentOffset, 226 value,key); 227 228 printf("%s\n", austrdup(result) ); 229 } 230 231 } 232 233 return; 234 235} 236err=U_ZERO_ERROR; 237} 238``` 239 240### Java 241 242```java 243import com.ibm.icu.text.*; 244import java.util.Date; 245import java.text.FieldPosition; 246 247public class TestMessageFormat{ 248 public void runTest() { 249 String format = "At {1,time,::jmm} on {1,date,::dMMMM}, there was {2} on planet {3,number,integer}."; 250 MessageFormat mf = new MessageFormat(format); 251 Object objectsToFormat[] = { new Date(System.currentTimeMillis()), new Date(System.currentTimeMillis()), "a Disturbance in the Force", new Integer(5)}; 252 FieldPosition fp = new FieldPosition(1); 253 StringBuffer sb = new StringBuffer(); 254 try{ 255 sb = mf.format(objectsToFormat, sb, fp); 256 System.out.println(sb.toString()); 257 }catch(IllegalArgumentException e){ 258 System.out.println("Exception during formatting of type :" +e); 259 } 260 } 261 262 public static void main(String args[]){ 263 try{ 264 new TestMessageFormat().runTest(); 265 }catch(Exception e){ 266 System.out.println("Exception of type: "+e); 267 } 268 } 269} 270``` 271 272## `ChoiceFormat` Class 273 274**Important:** The following documentation is outdated. *`ChoiceFormat` is 275probably not what you need. Please use `MessageFormat` with plural arguments for 276proper plural selection, and select arguments for simple selection among a fixed 277set of choices!* 278 279ICU's `ChoiceFormat` class provides more flexibility than the `printf()` and `scanf()` 280style functions for formatting UI strings. This interface can be useful if you 281would like a message to change according to the number of items you are 282displaying. 283 284Note: Some Asian languages do not have plural words or phrases. 285 286### C++ 287 288```cpp 289void msgSample1(){ 290 291 UChar *result, *tzID, *str; 292 UChar pattern[100]; 293 int32_t resultLengthOut, resultlength; 294 UCalendar *cal; 295 UDate d1; 296 UErrorCode status = U_ZERO_ERROR; 297 str=(UChar*)malloc(sizeof(UChar) * (strlen("disturbance in force") +1)); 298 u_uastrcpy(str, "disturbance in force"); 299 tzID=(UChar*)malloc(sizeof(UChar) * 4); 300 u_uastrcpy(tzID, "PST"); 301 cal=ucal_open(tzID, u_strlen(tzID), "en_US", UCAL_TRADITIONAL, &status); 302 ucal_setDateTime(cal, 1999, UCAL_MARCH, 18, 0, 0, 0, &status); 303 d1=ucal_getMillis(cal, &status); 304 u_uastrcpy(pattern, "On {0, date, long}, there was a {1} on planet 305 306{2,number,integer}"); 307 resultlength=0; 308 resultLengthOut=u_formatMessage( "en_US", pattern, u_strlen(pattern), 309NULL, 310resultlength, &status, d1, str, 7); 311 if(status==U_BUFFER_OVERFLOW_ERROR){ 312 status=U_ZERO_ERROR; 313 resultlength=resultLengthOut+1; 314 result=(UChar*)realloc(result, sizeof(UChar) * resultlength); 315 u_formatMessage( "en_US", pattern, u_strlen(pattern), result, 316resultlength, &status, d1, str, 7); 317 } 318 printf("%s\n",austrdup(result) ); //austrdup( a function used to convert 319UChar* to char*) 320 free(tzID); 321 free(str); 322double filelimits[] = {0,1,2}; 323UErrorCode err; 324UnicodeString filepart[] = {"are no files","is one file","are {2} files"}; 325ChoiceFormat fileform(filelimits, filepart,err); 326Format testFormats[] = {fileform, null, NumberFormat.getInstance()}; 327MessageFormat pattform("There {0} on {1}",err); 328pattform.setFormats(testFormats); 329Formattable testArgs[] = {null, "ADisk", null}; 330for (int i = 0; i < 4; ++i) { 331 testArgs[0] = i; 332 testArgs[2] = testArgs[0]; 333 FieldPosition fpos=0; 334 format.format(args,1, result,fpos,mError); 335 UnicodeString result = pattform.format(testArgs); 336} 337``` 338 339### C 340 341```c 342void msgSample2(){ 343 UChar* str; 344 UErrorCode status = U_ZERO_ERROR; 345 UChar *result; 346 UChar pattern[100]; 347 int32_t resultlength,resultLengthOut, i; 348 double testArgs[3]= { 100.0, 1.0, 0.0}; 349 str=(UChar*)malloc(sizeof(UChar) * 10); 350 u_uastrcpy(str, "MyDisk"); 351 u_uastrcpy(pattern, "The disk {1} contains {0,choice,0#no files|1#one 352file|1<{0,number,integer} files}"); 353 for(i=0; i<3; i++){ 354 resultlength=0; 355 resultLengthOut=u_formatMessage( "en_US", pattern, u_strlen(pattern), 356NULL, resultlength, &status, testArgs[i], str); 357 if(status==U_BUFFER_OVERFLOW_ERROR){ 358 status=U_ZERO_ERROR; 359 resultlength=resultLengthOut+1; 360 result=(UChar*)malloc(sizeof(UChar) * resultlength); 361 u_formatMessage( "en_US", pattern, u_strlen(pattern), result, 362resultlength, &status, testArgs[i], str); 363 } 364 } 365 printf("%s\n", austrdup(result) ); //austrdup( a function used to 366convert 367UChar* to char*) 368 free(result); 369 370} 371``` 372 373### Java 374 375```java 376import java.text.ChoiceFormat; 377import com.ibm.icu.text.*; 378import java.text.Format; 379 380public class TestChoiceFormat{ 381 public void run(){ 382 double[] filelimits = {0,1,2}; 383 String[] filepart = {"are no files","is one file","are {2} files"}; 384 ChoiceFormat fileform = new ChoiceFormat(filelimits,filepart); 385 Format[] testFormats = {fileform,null,NumberFormat.getInstance()}; 386 MessageFormat pattform = new MessageFormat("There {0} on {1}"); 387 Object[] testArgs = {null,"ADisk",null}; 388 for(int i=0;i<4;++i) { 389 testArgs[0] = new Integer(i); 390 testArgs[2] = testArgs[0]; 391 System.out.println(pattform.format(testArgs)); 392 } 393 } 394 395 public static void main(String args[]){ 396 new TestChoiceFormat().run(); 397 } 398} 399``` 400