1 29 30 package com.caucho.quercus.lib.gettext; 31 32 import com.caucho.quercus.annotation.Optional; 33 import com.caucho.quercus.env.*; 34 import com.caucho.quercus.lib.string.StringModule; 35 import com.caucho.quercus.module.AbstractQuercusModule; 36 import com.caucho.util.L10N; 37 import com.caucho.util.LruCache; 38 import com.caucho.vfs.Path; 39 40 import java.util.ArrayList ; 41 import java.util.HashMap ; 42 import java.util.Locale ; 43 import java.util.logging.Logger ; 44 45 46 50 public class GettextModule 51 extends AbstractQuercusModule 52 { 53 private LruCache<Object ,GettextResource> _cache = 54 new LruCache<Object ,GettextResource>(16); 55 56 private final Logger log 57 = Logger.getLogger(GettextModule.class.getName()); 58 private final L10N L = new L10N(GettextModule.class); 59 60 public String []getLoadedExtensions() 61 { 62 return new String [] { "gettext" }; 63 } 64 65 73 public StringValue bind_textdomain_codeset(Env env, 74 StringValue domain, 75 StringValue codeset) 76 { 77 return new StringValueImpl("UTF-16"); 78 } 79 80 88 public Value bindtextdomain(Env env, 89 StringValue domain, 90 StringValue directory) 91 { 92 return setPath(env, domain, directory); 93 } 94 95 103 public StringValue dcgettext(Env env, 104 StringValue domain, 105 StringValue message, 106 int category, 107 Value args[]) 108 { 109 return translate(env, 110 domain, 111 getCategory(env, category), 112 message, 113 args); 114 } 115 116 126 public StringValue dcngettext(Env env, 127 StringValue domain, 128 StringValue msgid1, 129 StringValue msgid2, 130 int n, 131 int category, 132 Value args[]) 133 { 134 return translate(env, 135 domain, 136 getCategory(env, category), 137 msgid1, 138 msgid2, 139 n, 140 args); 141 } 142 143 150 public StringValue dgettext(Env env, 151 StringValue domain, 152 StringValue message, 153 Value args[]) 154 { 155 return translate(env, 156 domain, 157 "LC_MESSAGES", 158 message, 159 args); 160 } 161 162 171 public StringValue dngettext(Env env, 172 StringValue domain, 173 StringValue msgid1, 174 StringValue msgid2, 175 int n, 176 Value args[]) 177 { 178 return translate(env, 179 domain, 180 "LC_MESSAGES", 181 msgid1, 182 msgid2, 183 n, 184 args); 185 } 186 187 193 public StringValue _(Env env, StringValue message, Value []args) 194 { 195 return gettext(env, message, args); 196 } 197 198 204 public StringValue gettext(Env env, StringValue message, Value []args) 205 { 206 return translate(env, 207 getCurrentDomain(env), 208 "LC_MESSAGES", 209 message, 210 args); 211 } 212 213 224 public StringValue ngettext(Env env, 225 StringValue msgid1, 226 StringValue msgid2, 227 int n, 228 Value args[]) 229 { 230 return translate(env, 231 getCurrentDomain(env), 232 "LC_MESSAGES", 233 msgid1, 234 msgid2, 235 n, 236 args); 237 } 238 239 246 public StringValue textdomain(Env env, 247 @Optional Value domain) 248 { 249 if (! domain.isNull()) 250 return setCurrentDomain(env, domain.toStringValue()); 251 252 return getCurrentDomain(env); 253 } 254 255 265 private StringValue translate(Env env, 266 StringValue domain, 267 CharSequence category, 268 StringValue message, 269 Value []args) 270 { 271 Locale locale = env.getLocaleInfo().getMessages(); 272 273 GettextResource resource = getResource(env, 274 getPath(env, domain), 275 locale, 276 category, 277 domain); 278 279 StringValue translation = resource.getTranslation(message); 280 281 if (translation == null) 282 translation = message; 283 284 return format(env, translation, args); 285 } 286 287 298 private StringValue translate(Env env, 299 StringValue domain, 300 CharSequence category, 301 StringValue msgid1, 302 StringValue msgid2, 303 int quantity, 304 Value []args) 305 { 306 Locale locale = env.getLocaleInfo().getMessages(); 307 308 GettextResource resource = getResource(env, 309 getPath(env, domain), 310 locale, 311 category, 312 domain); 313 314 StringValue translation = resource.getTranslation(msgid1, quantity); 315 316 if (translation == null) 317 translation = errorReturn(msgid1, msgid2, quantity); 318 319 return format(env, translation, args); 320 } 321 322 private GettextResource getResource(Env env, 323 Path path, 324 Locale locale, 325 CharSequence category, 326 StringValue domain) 327 { 328 ArrayList <Object > key = new ArrayList <Object >(); 329 330 key.add(path.getFullPath()); 331 key.add(locale); 332 key.add(category); 333 key.add(domain); 334 335 GettextResource resource = _cache.get(key); 336 337 if (resource == null) { 338 resource = new GettextResource(env, path, locale, category, domain); 339 _cache.put(key, resource); 340 } 341 342 return resource; 343 } 344 345 private Path getPath(Env env, StringValue domain) 346 { 347 Object val = env.getSpecialValue("caucho.gettext_paths"); 348 349 if (val == null) { 350 val = new HashMap <StringValue,Path>(); 351 352 env.setSpecialValue("caucho.gettext_paths", val); 353 } 354 355 Path path = ((HashMap <StringValue,Path>)val).get(domain); 356 357 if (path == null) 358 return env.getPwd(); 359 360 return path; 361 } 362 363 private Value setPath(Env env, 364 StringValue domain, 365 StringValue directory) 366 { 367 Object val = env.getSpecialValue("caucho.gettext_paths"); 368 369 if (val == null) { 370 val = new HashMap <StringValue,Path>(); 371 372 env.setSpecialValue("caucho.gettext_paths", val); 373 } 374 375 Path path = env.lookupPwd(directory); 376 377 if (path == null) 378 return BooleanValue.FALSE; 379 380 ((HashMap <StringValue,Path>)val).put(domain, path); 381 382 return directory; 383 } 384 385 private StringValue getCurrentDomain(Env env) 386 { 387 Object val = env.getSpecialValue("caucho.gettext_current"); 388 389 if (val == null) 390 return setCurrentDomain(env, new StringValueImpl("messages")); 391 392 return (StringValue)val; 393 } 394 395 private StringValue setCurrentDomain(Env env, StringValue currentDomain) 396 { 397 env.setSpecialValue("caucho.gettext_current", currentDomain); 398 399 return currentDomain; 400 } 401 402 405 private String getCategory(Env env, int category) 406 { 407 if (category == StringModule.LC_MESSAGES) 408 return "LC_MESSAGES"; 409 else if (category == StringModule.LC_ALL) 410 return "LC_ALL"; 411 else if (category == StringModule.LC_CTYPE) 412 return "LC_CTYPE"; 413 else if (category == StringModule.LC_NUMERIC) 414 return "LC_NUMERIC"; 415 else if (category == StringModule.LC_TIME) 416 return "LC_TIME"; 417 else if (category == StringModule.LC_COLLATE) 418 return "LC_COLLATE"; 419 else if (category == StringModule.LC_MONETARY) 420 return "LC_MONETARY"; 421 else { 422 env.warning(L.l("Invalid category. Please use named constants")); 423 return "LC_MESSAGES"; 424 } 425 } 426 427 private static StringValue errorReturn(StringValue msgid1, 428 StringValue msgid2, 429 int n) 430 { 431 if (n == 1) 432 return msgid1; 433 else 434 return msgid2; 435 } 436 437 private static StringValue format(Env env, 438 StringValue msg, 439 Value []args) 440 { 441 if (args.length == 0) 442 return msg; 443 else if (msg.isUnicode()) 444 return formatUnicode(env, msg, args); 445 else 446 return formatBinary(env, msg, args); 447 } 448 449 private static BinaryValue formatBinary(Env env, 450 StringValue msg, 451 Value []args) 452 { 453 BinaryBuilderValue sb = new BinaryBuilderValue(); 454 455 int i = 0; 456 int length = msg.length(); 457 458 while (i < length) { 459 char ch = msg.charAt(i); 460 461 if (ch != '[' || i + 4 > length) { 462 sb.appendByte(ch); 463 i++; 464 } 465 else if (msg.charAt(i + 1) != '_') { 466 sb.appendByte('['); 467 i++; 468 } 469 else if (msg.charAt(i + 3) != ']') { 470 sb.appendByte('['); 471 sb.appendByte('_'); 472 i += 2; 473 } 474 else { 475 ch = msg.charAt(i + 2); 476 int argIndex = ch - '0'; 477 478 if (0 <= argIndex && argIndex < args.length) { 479 args[argIndex].appendTo(sb); 480 i += 4; 481 } 482 else { 483 sb.appendByte('{'); 484 i++; 485 } 486 } 487 } 488 489 return sb; 490 } 491 492 private static UnicodeValue formatUnicode(Env env, 493 StringValue msg, 494 Value []args) 495 { 496 StringBuilderValue sb = new StringBuilderValue(); 497 498 int i = 0; 499 int length = msg.length(); 500 501 while (i < length) { 502 char ch = msg.charAt(i); 503 504 if (ch != '[' || i + 4 > length) { 505 sb.append(ch); 506 i++; 507 } 508 else if (msg.charAt(i + 1) != '_') { 509 sb.append(ch); 510 i++; 511 } 512 else if (msg.charAt(i + 3) != ']') { 513 sb.append(ch); 514 i++; 515 } 516 else { 517 ch = msg.charAt(i + 2); 518 int argIndex = ch - '0'; 519 520 if (0 <= argIndex && argIndex < args.length) { 521 args[argIndex].appendTo(sb); 522 i += 4; 523 } 524 else { 525 sb.append('['); 526 i++; 527 } 528 } 529 } 530 531 return sb; 532 } 533 } 534 | Popular Tags |