1 2# Time-stamp: "2004-01-11 18:35:34 AST" 3 4=head1 NAME 5 6Locale::Maketext - framework for localization 7 8=head1 SYNOPSIS 9 10 package MyProgram; 11 use strict; 12 use MyProgram::L10N; 13 # ...which inherits from Locale::Maketext 14 my $lh = MyProgram::L10N->get_handle() || die "What language?"; 15 ... 16 # And then any messages your program emits, like: 17 warn $lh->maketext( "Can't open file [_1]: [_2]\n", $f, $! ); 18 ... 19 20=head1 DESCRIPTION 21 22It is a common feature of applications (whether run directly, 23or via the Web) for them to be "localized" -- i.e., for them 24to a present an English interface to an English-speaker, a German 25interface to a German-speaker, and so on for all languages it's 26programmed with. Locale::Maketext 27is a framework for software localization; it provides you with the 28tools for organizing and accessing the bits of text and text-processing 29code that you need for producing localized applications. 30 31In order to make sense of Maketext and how all its 32components fit together, you should probably 33go read L<Locale::Maketext::TPJ13|Locale::Maketext::TPJ13>, and 34I<then> read the following documentation. 35 36You may also want to read over the source for C<File::Findgrep> 37and its constituent modules -- they are a complete (if small) 38example application that uses Maketext. 39 40=head1 QUICK OVERVIEW 41 42The basic design of Locale::Maketext is object-oriented, and 43Locale::Maketext is an abstract base class, from which you 44derive a "project class". 45The project class (with a name like "TkBocciBall::Localize", 46which you then use in your module) is in turn the base class 47for all the "language classes" for your project 48(with names "TkBocciBall::Localize::it", 49"TkBocciBall::Localize::en", 50"TkBocciBall::Localize::fr", etc.). 51 52A language class is 53a class containing a lexicon of phrases as class data, 54and possibly also some methods that are of use in interpreting 55phrases in the lexicon, or otherwise dealing with text in that 56language. 57 58An object belonging to a language class is called a "language 59handle"; it's typically a flyweight object. 60 61The normal course of action is to call: 62 63 use TkBocciBall::Localize; # the localization project class 64 $lh = TkBocciBall::Localize->get_handle(); 65 # Depending on the user's locale, etc., this will 66 # make a language handle from among the classes available, 67 # and any defaults that you declare. 68 die "Couldn't make a language handle??" unless $lh; 69 70From then on, you use the C<maketext> function to access 71entries in whatever lexicon(s) belong to the language handle 72you got. So, this: 73 74 print $lh->maketext("You won!"), "\n"; 75 76...emits the right text for this language. If the object 77in C<$lh> belongs to class "TkBocciBall::Localize::fr" and 78%TkBocciBall::Localize::fr::Lexicon contains C<("You won!" 79=E<gt> "Tu as gagnE<eacute>!")>, then the above 80code happily tells the user "Tu as gagnE<eacute>!". 81 82=head1 METHODS 83 84Locale::Maketext offers a variety of methods, which fall 85into three categories: 86 87=over 88 89=item * 90 91Methods to do with constructing language handles. 92 93=item * 94 95C<maketext> and other methods to do with accessing %Lexicon data 96for a given language handle. 97 98=item * 99 100Methods that you may find it handy to use, from routines of 101yours that you put in %Lexicon entries. 102 103=back 104 105These are covered in the following section. 106 107=head2 Construction Methods 108 109These are to do with constructing a language handle: 110 111=over 112 113=item * 114 115$lh = YourProjClass->get_handle( ...langtags... ) || die "lg-handle?"; 116 117This tries loading classes based on the language-tags you give (like 118C<("en-US", "sk", "kon", "es-MX", "ja", "i-klingon")>, and for the first class 119that succeeds, returns YourProjClass::I<language>->new(). 120 121If it runs thru the entire given list of language-tags, and finds no classes 122for those exact terms, it then tries "superordinate" language classes. 123So if no "en-US" class (i.e., YourProjClass::en_us) 124was found, nor classes for anything else in that list, we then try 125its superordinate, "en" (i.e., YourProjClass::en), and so on thru 126the other language-tags in the given list: "es". 127(The other language-tags in our example list: 128happen to have no superordinates.) 129 130If none of those language-tags leads to loadable classes, we then 131try classes derived from YourProjClass->fallback_languages() and 132then if nothing comes of that, we use classes named by 133YourProjClass->fallback_language_classes(). Then in the (probably 134quite unlikely) event that that fails, we just return undef. 135 136=item * 137 138$lh = YourProjClass->get_handleB<()> || die "lg-handle?"; 139 140When C<get_handle> is called with an empty parameter list, magic happens: 141 142If C<get_handle> senses that it's running in program that was 143invoked as a CGI, then it tries to get language-tags out of the 144environment variable "HTTP_ACCEPT_LANGUAGE", and it pretends that 145those were the languages passed as parameters to C<get_handle>. 146 147Otherwise (i.e., if not a CGI), this tries various OS-specific ways 148to get the language-tags for the current locale/language, and then 149pretends that those were the value(s) passed to C<get_handle>. 150 151Currently this OS-specific stuff consists of looking in the environment 152variables "LANG" and "LANGUAGE"; and on MSWin machines (where those 153variables are typically unused), this also tries using 154the module Win32::Locale to get a language-tag for whatever language/locale 155is currently selected in the "Regional Settings" (or "International"?) 156Control Panel. I welcome further 157suggestions for making this do the Right Thing under other operating 158systems that support localization. 159 160If you're using localization in an application that keeps a configuration 161file, you might consider something like this in your project class: 162 163 sub get_handle_via_config { 164 my $class = $_[0]; 165 my $chosen_language = $Config_settings{'language'}; 166 my $lh; 167 if($chosen_language) { 168 $lh = $class->get_handle($chosen_language) 169 || die "No language handle for \"$chosen_language\"" 170 . " or the like"; 171 } else { 172 # Config file missing, maybe? 173 $lh = $class->get_handle() 174 || die "Can't get a language handle"; 175 } 176 return $lh; 177 } 178 179=item * 180 181$lh = YourProjClass::langname->new(); 182 183This constructs a language handle. You usually B<don't> call this 184directly, but instead let C<get_handle> find a language class to C<use> 185and to then call ->new on. 186 187=item * 188 189$lh->init(); 190 191This is called by ->new to initialize newly-constructed language handles. 192If you define an init method in your class, remember that it's usually 193considered a good idea to call $lh->SUPER::init in it (presumably at the 194beginning), so that all classes get a chance to initialize a new object 195however they see fit. 196 197=item * 198 199YourProjClass->fallback_languages() 200 201C<get_handle> appends the return value of this to the end of 202whatever list of languages you pass C<get_handle>. Unless 203you override this method, your project class 204will inherit Locale::Maketext's C<fallback_languages>, which 205currently returns C<('i-default', 'en', 'en-US')>. 206("i-default" is defined in RFC 2277). 207 208This method (by having it return the name 209of a language-tag that has an existing language class) 210can be used for making sure that 211C<get_handle> will always manage to construct a language 212handle (assuming your language classes are in an appropriate 213@INC directory). Or you can use the next method: 214 215=item * 216 217YourProjClass->fallback_language_classes() 218 219C<get_handle> appends the return value of this to the end 220of the list of classes it will try using. Unless 221you override this method, your project class 222will inherit Locale::Maketext's C<fallback_language_classes>, 223which currently returns an empty list, C<()>. 224By setting this to some value (namely, the name of a loadable 225language class), you can be sure that 226C<get_handle> will always manage to construct a language 227handle. 228 229=back 230 231=head2 The "maketext" Method 232 233This is the most important method in Locale::Maketext: 234 235 $text = $lh->maketext(I<key>, ...parameters for this phrase...); 236 237This looks in the %Lexicon of the language handle 238$lh and all its superclasses, looking 239for an entry whose key is the string I<key>. Assuming such 240an entry is found, various things then happen, depending on the 241value found: 242 243If the value is a scalarref, the scalar is dereferenced and returned 244(and any parameters are ignored). 245 246If the value is a coderef, we return &$value($lh, ...parameters...). 247 248If the value is a string that I<doesn't> look like it's in Bracket Notation, 249we return it (after replacing it with a scalarref, in its %Lexicon). 250 251If the value I<does> look like it's in Bracket Notation, then we compile 252it into a sub, replace the string in the %Lexicon with the new coderef, 253and then we return &$new_sub($lh, ...parameters...). 254 255Bracket Notation is discussed in a later section. Note 256that trying to compile a string into Bracket Notation can throw 257an exception if the string is not syntactically valid (say, by not 258balancing brackets right.) 259 260Also, calling &$coderef($lh, ...parameters...) can throw any sort of 261exception (if, say, code in that sub tries to divide by zero). But 262a very common exception occurs when you have Bracket 263Notation text that says to call a method "foo", but there is no such 264method. (E.g., "You have [quaB<tn>,_1,ball]." will throw an exception 265on trying to call $lh->quaB<tn>($_[1],'ball') -- you presumably meant 266"quant".) C<maketext> catches these exceptions, but only to make the 267error message more readable, at which point it rethrows the exception. 268 269An exception I<may> be thrown if I<key> is not found in any 270of $lh's %Lexicon hashes. What happens if a key is not found, 271is discussed in a later section, "Controlling Lookup Failure". 272 273Note that you might find it useful in some cases to override 274the C<maketext> method with an "after method", if you want to 275translate encodings, or even scripts: 276 277 package YrProj::zh_cn; # Chinese with PRC-style glyphs 278 use base ('YrProj::zh_tw'); # Taiwan-style 279 sub maketext { 280 my $self = shift(@_); 281 my $value = $self->maketext(@_); 282 return Chineeze::taiwan2mainland($value); 283 } 284 285Or you may want to override it with something that traps 286any exceptions, if that's critical to your program: 287 288 sub maketext { 289 my($lh, @stuff) = @_; 290 my $out; 291 eval { $out = $lh->SUPER::maketext(@stuff) }; 292 return $out unless $@; 293 ...otherwise deal with the exception... 294 } 295 296Other than those two situations, I don't imagine that 297it's useful to override the C<maketext> method. (If 298you run into a situation where it is useful, I'd be 299interested in hearing about it.) 300 301=over 302 303=item $lh->fail_with I<or> $lh->fail_with(I<PARAM>) 304 305=item $lh->failure_handler_auto 306 307These two methods are discussed in the section "Controlling 308Lookup Failure". 309 310=item $lh->blacklist(@list) 311 312=item $lh->whitelist(@list) 313 314These methods are discussed in the section "Bracket Notation 315Security". 316 317=back 318 319=head2 Utility Methods 320 321These are methods that you may find it handy to use, generally 322from %Lexicon routines of yours (whether expressed as 323Bracket Notation or not). 324 325=over 326 327=item $language->quant($number, $singular) 328 329=item $language->quant($number, $singular, $plural) 330 331=item $language->quant($number, $singular, $plural, $negative) 332 333This is generally meant to be called from inside Bracket Notation 334(which is discussed later), as in 335 336 "Your search matched [quant,_1,document]!" 337 338It's for I<quantifying> a noun (i.e., saying how much of it there is, 339while giving the correct form of it). The behavior of this method is 340handy for English and a few other Western European languages, and you 341should override it for languages where it's not suitable. You can feel 342free to read the source, but the current implementation is basically 343as this pseudocode describes: 344 345 if $number is 0 and there's a $negative, 346 return $negative; 347 elsif $number is 1, 348 return "1 $singular"; 349 elsif there's a $plural, 350 return "$number $plural"; 351 else 352 return "$number " . $singular . "s"; 353 # 354 # ...except that we actually call numf to 355 # stringify $number before returning it. 356 357So for English (with Bracket Notation) 358C<"...[quant,_1,file]..."> is fine (for 0 it returns "0 files", 359for 1 it returns "1 file", and for more it returns "2 files", etc.) 360 361But for "directory", you'd want C<"[quant,_1,directory,directories]"> 362so that our elementary C<quant> method doesn't think that the 363plural of "directory" is "directorys". And you might find that the 364output may sound better if you specify a negative form, as in: 365 366 "[quant,_1,file,files,No files] matched your query.\n" 367 368Remember to keep in mind verb agreement (or adjectives too, in 369other languages), as in: 370 371 "[quant,_1,document] were matched.\n" 372 373Because if _1 is one, you get "1 document B<were> matched". 374An acceptable hack here is to do something like this: 375 376 "[quant,_1,document was, documents were] matched.\n" 377 378=item $language->numf($number) 379 380This returns the given number formatted nicely according to 381this language's conventions. Maketext's default method is 382mostly to just take the normal string form of the number 383(applying sprintf "%G" for only very large numbers), and then 384to add commas as necessary. (Except that 385we apply C<tr/,./.,/> if $language->{'numf_comma'} is true; 386that's a bit of a hack that's useful for languages that express 387two million as "2.000.000" and not as "2,000,000"). 388 389If you want anything fancier, consider overriding this with something 390that uses L<Number::Format|Number::Format>, or does something else 391entirely. 392 393Note that numf is called by quant for stringifying all quantifying 394numbers. 395 396=item $language->numerate($number, $singular, $plural, $negative) 397 398This returns the given noun form which is appropriate for the quantity 399C<$number> according to this language's conventions. C<numerate> is 400used internally by C<quant> to quantify nouns. Use it directly -- 401usually from bracket notation -- to avoid C<quant>'s implicit call to 402C<numf> and output of a numeric quantity. 403 404=item $language->sprintf($format, @items) 405 406This is just a wrapper around Perl's normal C<sprintf> function. 407It's provided so that you can use "sprintf" in Bracket Notation: 408 409 "Couldn't access datanode [sprintf,%10x=~[%s~],_1,_2]!\n" 410 411returning... 412 413 Couldn't access datanode Stuff=[thangamabob]! 414 415=item $language->language_tag() 416 417Currently this just takes the last bit of C<ref($language)>, turns 418underscores to dashes, and returns it. So if $language is 419an object of class Hee::HOO::Haw::en_us, $language->language_tag() 420returns "en-us". (Yes, the usual representation for that language 421tag is "en-US", but case is I<never> considered meaningful in 422language-tag comparison.) 423 424You may override this as you like; Maketext doesn't use it for 425anything. 426 427=item $language->encoding() 428 429Currently this isn't used for anything, but it's provided 430(with default value of 431C<(ref($language) && $language-E<gt>{'encoding'})) or "iso-8859-1"> 432) as a sort of suggestion that it may be useful/necessary to 433associate encodings with your language handles (whether on a 434per-class or even per-handle basis.) 435 436=back 437 438=head2 Language Handle Attributes and Internals 439 440A language handle is a flyweight object -- i.e., it doesn't (necessarily) 441carry any data of interest, other than just being a member of 442whatever class it belongs to. 443 444A language handle is implemented as a blessed hash. Subclasses of yours 445can store whatever data you want in the hash. Currently the only hash 446entry used by any crucial Maketext method is "fail", so feel free to 447use anything else as you like. 448 449B<Remember: Don't be afraid to read the Maketext source if there's 450any point on which this documentation is unclear.> This documentation 451is vastly longer than the module source itself. 452 453=head1 LANGUAGE CLASS HIERARCHIES 454 455These are Locale::Maketext's assumptions about the class 456hierarchy formed by all your language classes: 457 458=over 459 460=item * 461 462You must have a project base class, which you load, and 463which you then use as the first argument in 464the call to YourProjClass->get_handle(...). It should derive 465(whether directly or indirectly) from Locale::Maketext. 466It B<doesn't matter> how you name this class, although assuming this 467is the localization component of your Super Mega Program, 468good names for your project class might be 469SuperMegaProgram::Localization, SuperMegaProgram::L10N, 470SuperMegaProgram::I18N, SuperMegaProgram::International, 471or even SuperMegaProgram::Languages or SuperMegaProgram::Messages. 472 473=item * 474 475Language classes are what YourProjClass->get_handle will try to load. 476It will look for them by taking each language-tag (B<skipping> it 477if it doesn't look like a language-tag or locale-tag!), turning it to 478all lowercase, turning dashes to underscores, and appending it 479to YourProjClass . "::". So this: 480 481 $lh = YourProjClass->get_handle( 482 'en-US', 'fr', 'kon', 'i-klingon', 'i-klingon-romanized' 483 ); 484 485will try loading the classes 486YourProjClass::en_us (note lowercase!), YourProjClass::fr, 487YourProjClass::kon, 488YourProjClass::i_klingon 489and YourProjClass::i_klingon_romanized. (And it'll stop at the 490first one that actually loads.) 491 492=item * 493 494I assume that each language class derives (directly or indirectly) 495from your project class, and also defines its @ISA, its %Lexicon, 496or both. But I anticipate no dire consequences if these assumptions 497do not hold. 498 499=item * 500 501Language classes may derive from other language classes (although they 502should have "use I<Thatclassname>" or "use base qw(I<...classes...>)"). 503They may derive from the project 504class. They may derive from some other class altogether. Or via 505multiple inheritance, it may derive from any mixture of these. 506 507=item * 508 509I foresee no problems with having multiple inheritance in 510your hierarchy of language classes. (As usual, however, Perl will 511complain bitterly if you have a cycle in the hierarchy: i.e., if 512any class is its own ancestor.) 513 514=back 515 516=head1 ENTRIES IN EACH LEXICON 517 518A typical %Lexicon entry is meant to signify a phrase, 519taking some number (0 or more) of parameters. An entry 520is meant to be accessed by via 521a string I<key> in $lh->maketext(I<key>, ...parameters...), 522which should return a string that is generally meant for 523be used for "output" to the user -- regardless of whether 524this actually means printing to STDOUT, writing to a file, 525or putting into a GUI widget. 526 527While the key must be a string value (since that's a basic 528restriction that Perl places on hash keys), the value in 529the lexicon can currently be of several types: 530a defined scalar, scalarref, or coderef. The use of these is 531explained above, in the section 'The "maketext" Method', and 532Bracket Notation for strings is discussed in the next section. 533 534While you can use arbitrary unique IDs for lexicon keys 535(like "_min_larger_max_error"), it is often 536useful for if an entry's key is itself a valid value, like 537this example error message: 538 539 "Minimum ([_1]) is larger than maximum ([_2])!\n", 540 541Compare this code that uses an arbitrary ID... 542 543 die $lh->maketext( "_min_larger_max_error", $min, $max ) 544 if $min > $max; 545 546...to this code that uses a key-as-value: 547 548 die $lh->maketext( 549 "Minimum ([_1]) is larger than maximum ([_2])!\n", 550 $min, $max 551 ) if $min > $max; 552 553The second is, in short, more readable. In particular, it's obvious 554that the number of parameters you're feeding to that phrase (two) is 555the number of parameters that it I<wants> to be fed. (Since you see 556_1 and a _2 being used in the key there.) 557 558Also, once a project is otherwise 559complete and you start to localize it, you can scrape together 560all the various keys you use, and pass it to a translator; and then 561the translator's work will go faster if what he's presented is this: 562 563 "Minimum ([_1]) is larger than maximum ([_2])!\n", 564 => "", # fill in something here, Jacques! 565 566rather than this more cryptic mess: 567 568 "_min_larger_max_error" 569 => "", # fill in something here, Jacques 570 571I think that keys as lexicon values makes the completed lexicon 572entries more readable: 573 574 "Minimum ([_1]) is larger than maximum ([_2])!\n", 575 => "Le minimum ([_1]) est plus grand que le maximum ([_2])!\n", 576 577Also, having valid values as keys becomes very useful if you set 578up an _AUTO lexicon. _AUTO lexicons are discussed in a later 579section. 580 581I almost always use keys that are themselves 582valid lexicon values. One notable exception is when the value is 583quite long. For example, to get the screenful of data that 584a command-line program might return when given an unknown switch, 585I often just use a brief, self-explanatory key such as "_USAGE_MESSAGE". At that point I then go 586and immediately to define that lexicon entry in the 587ProjectClass::L10N::en lexicon (since English is always my "project 588language"): 589 590 '_USAGE_MESSAGE' => <<'EOSTUFF', 591 ...long long message... 592 EOSTUFF 593 594and then I can use it as: 595 596 getopt('oDI', \%opts) or die $lh->maketext('_USAGE_MESSAGE'); 597 598Incidentally, 599note that each class's C<%Lexicon> inherits-and-extends 600the lexicons in its superclasses. This is not because these are 601special hashes I<per se>, but because you access them via the 602C<maketext> method, which looks for entries across all the 603C<%Lexicon> hashes in a language class I<and> all its ancestor classes. 604(This is because the idea of "class data" isn't directly implemented 605in Perl, but is instead left to individual class-systems to implement 606as they see fit..) 607 608Note that you may have things stored in a lexicon 609besides just phrases for output: for example, if your program 610takes input from the keyboard, asking a "(Y/N)" question, 611you probably need to know what the equivalent of "Y[es]/N[o]" is 612in whatever language. You probably also need to know what 613the equivalents of the answers "y" and "n" are. You can 614store that information in the lexicon (say, under the keys 615"~answer_y" and "~answer_n", and the long forms as 616"~answer_yes" and "~answer_no", where "~" is just an ad-hoc 617character meant to indicate to programmers/translators that 618these are not phrases for output). 619 620Or instead of storing this in the language class's lexicon, 621you can (and, in some cases, really should) represent the same bit 622of knowledge as code in a method in the language class. (That 623leaves a tidy distinction between the lexicon as the things we 624know how to I<say>, and the rest of the things in the lexicon class 625as things that we know how to I<do>.) Consider 626this example of a processor for responses to French "oui/non" 627questions: 628 629 sub y_or_n { 630 return undef unless defined $_[1] and length $_[1]; 631 my $answer = lc $_[1]; # smash case 632 return 1 if $answer eq 'o' or $answer eq 'oui'; 633 return 0 if $answer eq 'n' or $answer eq 'non'; 634 return undef; 635 } 636 637...which you'd then call in a construct like this: 638 639 my $response; 640 until(defined $response) { 641 print $lh->maketext("Open the pod bay door (y/n)? "); 642 $response = $lh->y_or_n( get_input_from_keyboard_somehow() ); 643 } 644 if($response) { $pod_bay_door->open() } 645 else { $pod_bay_door->leave_closed() } 646 647Other data worth storing in a lexicon might be things like 648filenames for language-targetted resources: 649 650 ... 651 "_main_splash_png" 652 => "/styles/en_us/main_splash.png", 653 "_main_splash_imagemap" 654 => "/styles/en_us/main_splash.incl", 655 "_general_graphics_path" 656 => "/styles/en_us/", 657 "_alert_sound" 658 => "/styles/en_us/hey_there.wav", 659 "_forward_icon" 660 => "left_arrow.png", 661 "_backward_icon" 662 => "right_arrow.png", 663 # In some other languages, left equals 664 # BACKwards, and right is FOREwards. 665 ... 666 667You might want to do the same thing for expressing key bindings 668or the like (since hardwiring "q" as the binding for the function 669that quits a screen/menu/program is useful only if your language 670happens to associate "q" with "quit"!) 671 672=head1 BRACKET NOTATION 673 674Bracket Notation is a crucial feature of Locale::Maketext. I mean 675Bracket Notation to provide a replacement for the use of sprintf formatting. 676Everything you do with Bracket Notation could be done with a sub block, 677but bracket notation is meant to be much more concise. 678 679Bracket Notation is a like a miniature "template" system (in the sense 680of L<Text::Template|Text::Template>, not in the sense of C++ templates), 681where normal text is passed thru basically as is, but text in special 682regions is specially interpreted. In Bracket Notation, you use square brackets ("[...]"), 683not curly braces ("{...}") to note sections that are specially interpreted. 684 685For example, here all the areas that are taken literally are underlined with 686a "^", and all the in-bracket special regions are underlined with an X: 687 688 "Minimum ([_1]) is larger than maximum ([_2])!\n", 689 ^^^^^^^^^ XX ^^^^^^^^^^^^^^^^^^^^^^^^^^ XX ^^^^ 690 691When that string is compiled from bracket notation into a real Perl sub, 692it's basically turned into: 693 694 sub { 695 my $lh = $_[0]; 696 my @params = @_; 697 return join '', 698 "Minimum (", 699 ...some code here... 700 ") is larger than maximum (", 701 ...some code here... 702 ")!\n", 703 } 704 # to be called by $lh->maketext(KEY, params...) 705 706In other words, text outside bracket groups is turned into string 707literals. Text in brackets is rather more complex, and currently follows 708these rules: 709 710=over 711 712=item * 713 714Bracket groups that are empty, or which consist only of whitespace, 715are ignored. (Examples: "[]", "[ ]", or a [ and a ] with returns 716and/or tabs and/or spaces between them. 717 718Otherwise, each group is taken to be a comma-separated group of items, 719and each item is interpreted as follows: 720 721=item * 722 723An item that is "_I<digits>" or "_-I<digits>" is interpreted as 724$_[I<value>]. I.e., "_1" becomes with $_[1], and "_-3" is interpreted 725as $_[-3] (in which case @_ should have at least three elements in it). 726Note that $_[0] is the language handle, and is typically not named 727directly. 728 729=item * 730 731An item "_*" is interpreted to mean "all of @_ except $_[0]". 732I.e., C<@_[1..$#_]>. Note that this is an empty list in the case 733of calls like $lh->maketext(I<key>) where there are no 734parameters (except $_[0], the language handle). 735 736=item * 737 738Otherwise, each item is interpreted as a string literal. 739 740=back 741 742The group as a whole is interpreted as follows: 743 744=over 745 746=item * 747 748If the first item in a bracket group looks like a method name, 749then that group is interpreted like this: 750 751 $lh->that_method_name( 752 ...rest of items in this group... 753 ), 754 755=item * 756 757If the first item in a bracket group is "*", it's taken as shorthand 758for the so commonly called "quant" method. Similarly, if the first 759item in a bracket group is "#", it's taken to be shorthand for 760"numf". 761 762=item * 763 764If the first item in a bracket group is the empty-string, or "_*" 765or "_I<digits>" or "_-I<digits>", then that group is interpreted 766as just the interpolation of all its items: 767 768 join('', 769 ...rest of items in this group... 770 ), 771 772Examples: "[_1]" and "[,_1]", which are synonymous; and 773"C<[,ID-(,_4,-,_2,)]>", which compiles as 774C<join "", "ID-(", $_[4], "-", $_[2], ")">. 775 776=item * 777 778Otherwise this bracket group is invalid. For example, in the group 779"[!@#,whatever]", the first item C<"!@#"> is neither the empty-string, 780"_I<number>", "_-I<number>", "_*", nor a valid method name; and so 781Locale::Maketext will throw an exception of you try compiling an 782expression containing this bracket group. 783 784=back 785 786Note, incidentally, that items in each group are comma-separated, 787not C</\s*,\s*/>-separated. That is, you might expect that this 788bracket group: 789 790 "Hoohah [foo, _1 , bar ,baz]!" 791 792would compile to this: 793 794 sub { 795 my $lh = $_[0]; 796 return join '', 797 "Hoohah ", 798 $lh->foo( $_[1], "bar", "baz"), 799 "!", 800 } 801 802But it actually compiles as this: 803 804 sub { 805 my $lh = $_[0]; 806 return join '', 807 "Hoohah ", 808 $lh->foo(" _1 ", " bar ", "baz"), # note the <space> in " bar " 809 "!", 810 } 811 812In the notation discussed so far, the characters "[" and "]" are given 813special meaning, for opening and closing bracket groups, and "," has 814a special meaning inside bracket groups, where it separates items in the 815group. This begs the question of how you'd express a literal "[" or 816"]" in a Bracket Notation string, and how you'd express a literal 817comma inside a bracket group. For this purpose I've adopted "~" (tilde) 818as an escape character: "~[" means a literal '[' character anywhere 819in Bracket Notation (i.e., regardless of whether you're in a bracket 820group or not), and ditto for "~]" meaning a literal ']', and "~," meaning 821a literal comma. (Altho "," means a literal comma outside of 822bracket groups -- it's only inside bracket groups that commas are special.) 823 824And on the off chance you need a literal tilde in a bracket expression, 825you get it with "~~". 826 827Currently, an unescaped "~" before a character 828other than a bracket or a comma is taken to mean just a "~" and that 829character. I.e., "~X" means the same as "~~X" -- i.e., one literal tilde, 830and then one literal "X". However, by using "~X", you are assuming that 831no future version of Maketext will use "~X" as a magic escape sequence. 832In practice this is not a great problem, since first off you can just 833write "~~X" and not worry about it; second off, I doubt I'll add lots 834of new magic characters to bracket notation; and third off, you 835aren't likely to want literal "~" characters in your messages anyway, 836since it's not a character with wide use in natural language text. 837 838Brackets must be balanced -- every openbracket must have 839one matching closebracket, and vice versa. So these are all B<invalid>: 840 841 "I ate [quant,_1,rhubarb pie." 842 "I ate [quant,_1,rhubarb pie[." 843 "I ate quant,_1,rhubarb pie]." 844 "I ate quant,_1,rhubarb pie[." 845 846Currently, bracket groups do not nest. That is, you B<cannot> say: 847 848 "Foo [bar,baz,[quux,quuux]]\n"; 849 850If you need a notation that's that powerful, use normal Perl: 851 852 %Lexicon = ( 853 ... 854 "some_key" => sub { 855 my $lh = $_[0]; 856 join '', 857 "Foo ", 858 $lh->bar('baz', $lh->quux('quuux')), 859 "\n", 860 }, 861 ... 862 ); 863 864Or write the "bar" method so you don't need to pass it the 865output from calling quux. 866 867I do not anticipate that you will need (or particularly want) 868to nest bracket groups, but you are welcome to email me with 869convincing (real-life) arguments to the contrary. 870 871=head1 BRACKET NOTATION SECURITY 872 873Locale::Maketext does not use any special syntax to differentiate 874bracket notation methods from normal class or object methods. This 875design makes it vulnerable to format string attacks whenever it is 876used to process strings provided by untrusted users. 877 878Locale::Maketext does support blacklist and whitelist functionality 879to limit which methods may be called as bracket notation methods. 880 881By default, Locale::Maketext blacklists all methods in the 882Locale::Maketext namespace that begin with the '_' character, 883and all methods which include Perl's namespace separator characters. 884 885The default blacklist for Locale::Maketext also prevents use of the 886following methods in bracket notation: 887 888 blacklist 889 encoding 890 fail_with 891 failure_handler_auto 892 fallback_language_classes 893 fallback_languages 894 get_handle 895 init 896 language_tag 897 maketext 898 new 899 whitelist 900 901This list can be extended by either blacklisting additional "known bad" 902methods, or whitelisting only "known good" methods. 903 904To prevent specific methods from being called in bracket notation, use 905the blacklist() method: 906 907 my $lh = MyProgram::L10N->get_handle(); 908 $lh->blacklist(qw{my_internal_method my_other_method}); 909 $lh->maketext('[my_internal_method]'); # dies 910 911To limit the allowed bracked notation methods to a specific list, use the 912whitelist() method: 913 914 my $lh = MyProgram::L10N->get_handle(); 915 $lh->whitelist('numerate', 'numf'); 916 $lh->maketext('[_1] [numerate, _1,shoe,shoes]', 12); # works 917 $lh->maketext('[my_internal_method]'); # dies 918 919The blacklist() and whitelist() methods extend their internal lists 920whenever they are called. To reset the blacklist or whitelist, create 921a new maketext object. 922 923 my $lh = MyProgram::L10N->get_handle(); 924 $lh->blacklist('numerate'); 925 $lh->blacklist('numf'); 926 $lh->maketext('[_1] [numerate,_1,shoe,shoes]', 12); # dies 927 928For lexicons that use an internal cache, translations which have already 929been cached in their compiled form are not affected by subsequent changes 930to the whitelist or blacklist settings. Lexicons that use an external 931cache will have their cache cleared whenever the whitelist of blacklist 932setings change. The difference between the two types of caching is explained 933in the "Readonly Lexicons" section. 934 935Methods disallowed by the blacklist cannot be permitted by the 936whitelist. 937 938=head1 AUTO LEXICONS 939 940If maketext goes to look in an individual %Lexicon for an entry 941for I<key> (where I<key> does not start with an underscore), and 942sees none, B<but does see> an entry of "_AUTO" => I<some_true_value>, 943then we actually define $Lexicon{I<key>} = I<key> right then and there, 944and then use that value as if it had been there all 945along. This happens before we even look in any superclass %Lexicons! 946 947(This is meant to be somewhat like the AUTOLOAD mechanism in 948Perl's function call system -- or, looked at another way, 949like the L<AutoLoader|AutoLoader> module.) 950 951I can picture all sorts of circumstances where you just 952do not want lookup to be able to fail (since failing 953normally means that maketext throws a C<die>, although 954see the next section for greater control over that). But 955here's one circumstance where _AUTO lexicons are meant to 956be I<especially> useful: 957 958As you're writing an application, you decide as you go what messages 959you need to emit. Normally you'd go to write this: 960 961 if(-e $filename) { 962 go_process_file($filename) 963 } else { 964 print qq{Couldn't find file "$filename"!\n}; 965 } 966 967but since you anticipate localizing this, you write: 968 969 use ThisProject::I18N; 970 my $lh = ThisProject::I18N->get_handle(); 971 # For the moment, assume that things are set up so 972 # that we load class ThisProject::I18N::en 973 # and that that's the class that $lh belongs to. 974 ... 975 if(-e $filename) { 976 go_process_file($filename) 977 } else { 978 print $lh->maketext( 979 qq{Couldn't find file "[_1]"!\n}, $filename 980 ); 981 } 982 983Now, right after you've just written the above lines, you'd 984normally have to go open the file 985ThisProject/I18N/en.pm, and immediately add an entry: 986 987 "Couldn't find file \"[_1]\"!\n" 988 => "Couldn't find file \"[_1]\"!\n", 989 990But I consider that somewhat of a distraction from the work 991of getting the main code working -- to say nothing of the fact 992that I often have to play with the program a few times before 993I can decide exactly what wording I want in the messages (which 994in this case would require me to go changing three lines of code: 995the call to maketext with that key, and then the two lines in 996ThisProject/I18N/en.pm). 997 998However, if you set "_AUTO => 1" in the %Lexicon in, 999ThisProject/I18N/en.pm (assuming that English (en) is 1000the language that all your programmers will be using for this 1001project's internal message keys), then you don't ever have to 1002go adding lines like this 1003 1004 "Couldn't find file \"[_1]\"!\n" 1005 => "Couldn't find file \"[_1]\"!\n", 1006 1007to ThisProject/I18N/en.pm, because if _AUTO is true there, 1008then just looking for an entry with the key "Couldn't find 1009file \"[_1]\"!\n" in that lexicon will cause it to be added, 1010with that value! 1011 1012Note that the reason that keys that start with "_" 1013are immune to _AUTO isn't anything generally magical about 1014the underscore character -- I just wanted a way to have most 1015lexicon keys be autoable, except for possibly a few, and I 1016arbitrarily decided to use a leading underscore as a signal 1017to distinguish those few. 1018 1019=head1 READONLY LEXICONS 1020 1021If your lexicon is a tied hash the simple act of caching the compiled value can be fatal. 1022 1023For example a L<GDBM_File> GDBM_READER tied hash will die with something like: 1024 1025 gdbm store returned -1, errno 2, key "..." at ... 1026 1027All you need to do is turn on caching outside of the lexicon hash itself like so: 1028 1029 sub init { 1030 my ($lh) = @_; 1031 ... 1032 $lh->{'use_external_lex_cache'} = 1; 1033 ... 1034 } 1035 1036And then instead of storing the compiled value in the lexicon hash it will store it in $lh->{'_external_lex_cache'} 1037 1038=head1 CONTROLLING LOOKUP FAILURE 1039 1040If you call $lh->maketext(I<key>, ...parameters...), 1041and there's no entry I<key> in $lh's class's %Lexicon, nor 1042in the superclass %Lexicon hash, I<and> if we can't auto-make 1043I<key> (because either it starts with a "_", or because none 1044of its lexicons have C<_AUTO =E<gt> 1,>), then we have 1045failed to find a normal way to maketext I<key>. What then 1046happens in these failure conditions, depends on the $lh object's 1047"fail" attribute. 1048 1049If the language handle has no "fail" attribute, maketext 1050will simply throw an exception (i.e., it calls C<die>, mentioning 1051the I<key> whose lookup failed, and naming the line number where 1052the calling $lh->maketext(I<key>,...) was. 1053 1054If the language handle has a "fail" attribute whose value is a 1055coderef, then $lh->maketext(I<key>,...params...) gives up and calls: 1056 1057 return $that_subref->($lh, $key, @params); 1058 1059Otherwise, the "fail" attribute's value should be a string denoting 1060a method name, so that $lh->maketext(I<key>,...params...) can 1061give up with: 1062 1063 return $lh->$that_method_name($phrase, @params); 1064 1065The "fail" attribute can be accessed with the C<fail_with> method: 1066 1067 # Set to a coderef: 1068 $lh->fail_with( \&failure_handler ); 1069 1070 # Set to a method name: 1071 $lh->fail_with( 'failure_method' ); 1072 1073 # Set to nothing (i.e., so failure throws a plain exception) 1074 $lh->fail_with( undef ); 1075 1076 # Get the current value 1077 $handler = $lh->fail_with(); 1078 1079Now, as to what you may want to do with these handlers: Maybe you'd 1080want to log what key failed for what class, and then die. Maybe 1081you don't like C<die> and instead you want to send the error message 1082to STDOUT (or wherever) and then merely C<exit()>. 1083 1084Or maybe you don't want to C<die> at all! Maybe you could use a 1085handler like this: 1086 1087 # Make all lookups fall back onto an English value, 1088 # but only after we log it for later fingerpointing. 1089 my $lh_backup = ThisProject->get_handle('en'); 1090 open(LEX_FAIL_LOG, ">>wherever/lex.log") || die "GNAARGH $!"; 1091 sub lex_fail { 1092 my($failing_lh, $key, $params) = @_; 1093 print LEX_FAIL_LOG scalar(localtime), "\t", 1094 ref($failing_lh), "\t", $key, "\n"; 1095 return $lh_backup->maketext($key,@params); 1096 } 1097 1098Some users have expressed that they think this whole mechanism of 1099having a "fail" attribute at all, seems a rather pointless complication. 1100But I want Locale::Maketext to be usable for software projects of I<any> 1101scale and type; and different software projects have different ideas 1102of what the right thing is to do in failure conditions. I could simply 1103say that failure always throws an exception, and that if you want to be 1104careful, you'll just have to wrap every call to $lh->maketext in an 1105S<eval { }>. However, I want programmers to reserve the right (via 1106the "fail" attribute) to treat lookup failure as something other than 1107an exception of the same level of severity as a config file being 1108unreadable, or some essential resource being inaccessible. 1109 1110One possibly useful value for the "fail" attribute is the method name 1111"failure_handler_auto". This is a method defined in the class 1112Locale::Maketext itself. You set it with: 1113 1114 $lh->fail_with('failure_handler_auto'); 1115 1116Then when you call $lh->maketext(I<key>, ...parameters...) and 1117there's no I<key> in any of those lexicons, maketext gives up with 1118 1119 return $lh->failure_handler_auto($key, @params); 1120 1121But failure_handler_auto, instead of dying or anything, compiles 1122$key, caching it in 1123 1124 $lh->{'failure_lex'}{$key} = $compiled 1125 1126and then calls the compiled value, and returns that. (I.e., if 1127$key looks like bracket notation, $compiled is a sub, and we return 1128&{$compiled}(@params); but if $key is just a plain string, we just 1129return that.) 1130 1131The effect of using "failure_auto_handler" 1132is like an AUTO lexicon, except that it 1) compiles $key even if 1133it starts with "_", and 2) you have a record in the new hashref 1134$lh->{'failure_lex'} of all the keys that have failed for 1135this object. This should avoid your program dying -- as long 1136as your keys aren't actually invalid as bracket code, and as 1137long as they don't try calling methods that don't exist. 1138 1139"failure_auto_handler" may not be exactly what you want, but I 1140hope it at least shows you that maketext failure can be mitigated 1141in any number of very flexible ways. If you can formalize exactly 1142what you want, you should be able to express that as a failure 1143handler. You can even make it default for every object of a given 1144class, by setting it in that class's init: 1145 1146 sub init { 1147 my $lh = $_[0]; # a newborn handle 1148 $lh->SUPER::init(); 1149 $lh->fail_with('my_clever_failure_handler'); 1150 return; 1151 } 1152 sub my_clever_failure_handler { 1153 ...you clever things here... 1154 } 1155 1156=head1 HOW TO USE MAKETEXT 1157 1158Here is a brief checklist on how to use Maketext to localize 1159applications: 1160 1161=over 1162 1163=item * 1164 1165Decide what system you'll use for lexicon keys. If you insist, 1166you can use opaque IDs (if you're nostalgic for C<catgets>), 1167but I have better suggestions in the 1168section "Entries in Each Lexicon", above. Assuming you opt for 1169meaningful keys that double as values (like "Minimum ([_1]) is 1170larger than maximum ([_2])!\n"), you'll have to settle on what 1171language those should be in. For the sake of argument, I'll 1172call this English, specifically American English, "en-US". 1173 1174=item * 1175 1176Create a class for your localization project. This is 1177the name of the class that you'll use in the idiom: 1178 1179 use Projname::L10N; 1180 my $lh = Projname::L10N->get_handle(...) || die "Language?"; 1181 1182Assuming you call your class Projname::L10N, create a class 1183consisting minimally of: 1184 1185 package Projname::L10N; 1186 use base qw(Locale::Maketext); 1187 ...any methods you might want all your languages to share... 1188 1189 # And, assuming you want the base class to be an _AUTO lexicon, 1190 # as is discussed a few sections up: 1191 1192 1; 1193 1194=item * 1195 1196Create a class for the language your internal keys are in. Name 1197the class after the language-tag for that language, in lowercase, 1198with dashes changed to underscores. Assuming your project's first 1199language is US English, you should call this Projname::L10N::en_us. 1200It should consist minimally of: 1201 1202 package Projname::L10N::en_us; 1203 use base qw(Projname::L10N); 1204 %Lexicon = ( 1205 '_AUTO' => 1, 1206 ); 1207 1; 1208 1209(For the rest of this section, I'll assume that this "first 1210language class" of Projname::L10N::en_us has 1211_AUTO lexicon.) 1212 1213=item * 1214 1215Go and write your program. Everywhere in your program where 1216you would say: 1217 1218 print "Foobar $thing stuff\n"; 1219 1220instead do it thru maketext, using no variable interpolation in 1221the key: 1222 1223 print $lh->maketext("Foobar [_1] stuff\n", $thing); 1224 1225If you get tired of constantly saying C<print $lh-E<gt>maketext>, 1226consider making a functional wrapper for it, like so: 1227 1228 use Projname::L10N; 1229 our $lh; 1230 $lh = Projname::L10N->get_handle(...) || die "Language?"; 1231 sub pmt (@) { print( $lh->maketext(@_)) } 1232 # "pmt" is short for "Print MakeText" 1233 $Carp::Verbose = 1; 1234 # so if maketext fails, we see made the call to pmt 1235 1236Besides whole phrases meant for output, anything language-dependent 1237should be put into the class Projname::L10N::en_us, 1238whether as methods, or as lexicon entries -- this is discussed 1239in the section "Entries in Each Lexicon", above. 1240 1241=item * 1242 1243Once the program is otherwise done, and once its localization for 1244the first language works right (via the data and methods in 1245Projname::L10N::en_us), you can get together the data for translation. 1246If your first language lexicon isn't an _AUTO lexicon, then you already 1247have all the messages explicitly in the lexicon (or else you'd be 1248getting exceptions thrown when you call $lh->maketext to get 1249messages that aren't in there). But if you were (advisedly) lazy and are 1250using an _AUTO lexicon, then you've got to make a list of all the phrases 1251that you've so far been letting _AUTO generate for you. There are very 1252many ways to assemble such a list. The most straightforward is to simply 1253grep the source for every occurrence of "maketext" (or calls 1254to wrappers around it, like the above C<pmt> function), and to log the 1255following phrase. 1256 1257=item * 1258 1259You may at this point want to consider whether your base class 1260(Projname::L10N), from which all lexicons inherit from (Projname::L10N::en, 1261Projname::L10N::es, etc.), should be an _AUTO lexicon. It may be true 1262that in theory, all needed messages will be in each language class; 1263but in the presumably unlikely or "impossible" case of lookup failure, 1264you should consider whether your program should throw an exception, 1265emit text in English (or whatever your project's first language is), 1266or some more complex solution as described in the section 1267"Controlling Lookup Failure", above. 1268 1269=item * 1270 1271Submit all messages/phrases/etc. to translators. 1272 1273(You may, in fact, want to start with localizing to I<one> other language 1274at first, if you're not sure that you've properly abstracted the 1275language-dependent parts of your code.) 1276 1277Translators may request clarification of the situation in which a 1278particular phrase is found. For example, in English we are entirely happy 1279saying "I<n> files found", regardless of whether we mean "I looked for files, 1280and found I<n> of them" or the rather distinct situation of "I looked for 1281something else (like lines in files), and along the way I saw I<n> 1282files." This may involve rethinking things that you thought quite clear: 1283should "Edit" on a toolbar be a noun ("editing") or a verb ("to edit")? Is 1284there already a conventionalized way to express that menu option, separate 1285from the target language's normal word for "to edit"? 1286 1287In all cases where the very common phenomenon of quantification 1288(saying "I<N> files", for B<any> value of N) 1289is involved, each translator should make clear what dependencies the 1290number causes in the sentence. In many cases, dependency is 1291limited to words adjacent to the number, in places where you might 1292expect them ("I found the-?PLURAL I<N> 1293empty-?PLURAL directory-?PLURAL"), but in some cases there are 1294unexpected dependencies ("I found-?PLURAL ..."!) as well as long-distance 1295dependencies "The I<N> directory-?PLURAL could not be deleted-?PLURAL"!). 1296 1297Remind the translators to consider the case where N is 0: 1298"0 files found" isn't exactly natural-sounding in any language, but it 1299may be unacceptable in many -- or it may condition special 1300kinds of agreement (similar to English "I didN'T find ANY files"). 1301 1302Remember to ask your translators about numeral formatting in their 1303language, so that you can override the C<numf> method as 1304appropriate. Typical variables in number formatting are: what to 1305use as a decimal point (comma? period?); what to use as a thousands 1306separator (space? nonbreaking space? comma? period? small 1307middot? prime? apostrophe?); and even whether the so-called "thousands 1308separator" is actually for every third digit -- I've heard reports of 1309two hundred thousand being expressible as "2,00,000" for some Indian 1310(Subcontinental) languages, besides the less surprising "S<200 000>", 1311"200.000", "200,000", and "200'000". Also, using a set of numeral 1312glyphs other than the usual ASCII "0"-"9" might be appreciated, as via 1313C<tr/0-9/\x{0966}-\x{096F}/> for getting digits in Devanagari script 1314(for Hindi, Konkani, others). 1315 1316The basic C<quant> method that Locale::Maketext provides should be 1317good for many languages. For some languages, it might be useful 1318to modify it (or its constituent C<numerate> method) 1319to take a plural form in the two-argument call to C<quant> 1320(as in "[quant,_1,files]") if 1321it's all-around easier to infer the singular form from the plural, than 1322to infer the plural form from the singular. 1323 1324But for other languages (as is discussed at length 1325in L<Locale::Maketext::TPJ13|Locale::Maketext::TPJ13>), simple 1326C<quant>/C<numf> is not enough. For the particularly problematic 1327Slavic languages, what you may need is a method which you provide 1328with the number, the citation form of the noun to quantify, and 1329the case and gender that the sentence's syntax projects onto that 1330noun slot. The method would then be responsible for determining 1331what grammatical number that numeral projects onto its noun phrase, 1332and what case and gender it may override the normal case and gender 1333with; and then it would look up the noun in a lexicon providing 1334all needed inflected forms. 1335 1336=item * 1337 1338You may also wish to discuss with the translators the question of 1339how to relate different subforms of the same language tag, 1340considering how this reacts with C<get_handle>'s treatment of 1341these. For example, if a user accepts interfaces in "en, fr", and 1342you have interfaces available in "en-US" and "fr", what should 1343they get? You may wish to resolve this by establishing that "en" 1344and "en-US" are effectively synonymous, by having one class 1345zero-derive from the other. 1346 1347For some languages this issue may never come up (Danish is rarely 1348expressed as "da-DK", but instead is just "da"). And for other 1349languages, the whole concept of a "generic" form may verge on 1350being uselessly vague, particularly for interfaces involving voice 1351media in forms of Arabic or Chinese. 1352 1353=item * 1354 1355Once you've localized your program/site/etc. for all desired 1356languages, be sure to show the result (whether live, or via 1357screenshots) to the translators. Once they approve, make every 1358effort to have it then checked by at least one other speaker of 1359that language. This holds true even when (or especially when) the 1360translation is done by one of your own programmers. Some 1361kinds of systems may be harder to find testers for than others, 1362depending on the amount of domain-specific jargon and concepts 1363involved -- it's easier to find people who can tell you whether 1364they approve of your translation for "delete this message" in an 1365email-via-Web interface, than to find people who can give you 1366an informed opinion on your translation for "attribute value" 1367in an XML query tool's interface. 1368 1369=back 1370 1371=head1 SEE ALSO 1372 1373I recommend reading all of these: 1374 1375L<Locale::Maketext::TPJ13|Locale::Maketext::TPJ13> -- my I<The Perl 1376Journal> article about Maketext. It explains many important concepts 1377underlying Locale::Maketext's design, and some insight into why 1378Maketext is better than the plain old approach of having 1379message catalogs that are just databases of sprintf formats. 1380 1381L<File::Findgrep|File::Findgrep> is a sample application/module 1382that uses Locale::Maketext to localize its messages. For a larger 1383internationalized system, see also L<Apache::MP3>. 1384 1385L<I18N::LangTags|I18N::LangTags>. 1386 1387L<Win32::Locale|Win32::Locale>. 1388 1389RFC 3066, I<Tags for the Identification of Languages>, 1390as at L<http://sunsite.dk/RFC/rfc/rfc3066.html> 1391 1392RFC 2277, I<IETF Policy on Character Sets and Languages> 1393is at L<http://sunsite.dk/RFC/rfc/rfc2277.html> -- much of it is 1394just things of interest to protocol designers, but it explains 1395some basic concepts, like the distinction between locales and 1396language-tags. 1397 1398The manual for GNU C<gettext>. The gettext dist is available in 1399C<L<ftp://prep.ai.mit.edu/pub/gnu/>> -- get 1400a recent gettext tarball and look in its "doc/" directory, there's 1401an easily browsable HTML version in there. The 1402gettext documentation asks lots of questions worth thinking 1403about, even if some of their answers are sometimes wonky, 1404particularly where they start talking about pluralization. 1405 1406The Locale/Maketext.pm source. Observe that the module is much 1407shorter than its documentation! 1408 1409=head1 COPYRIGHT AND DISCLAIMER 1410 1411Copyright (c) 1999-2004 Sean M. Burke. All rights reserved. 1412 1413This library is free software; you can redistribute it and/or modify 1414it under the same terms as Perl itself. 1415 1416This program is distributed in the hope that it will be useful, but 1417without any warranty; without even the implied warranty of 1418merchantability or fitness for a particular purpose. 1419 1420=head1 AUTHOR 1421 1422Sean M. Burke C<sburke@cpan.org> 1423 1424=cut 1425