📄 maketext.pod
字号:
return $lh_backup->maketext($key,@params); }Some users have expressed that they think this whole mechanism ofhaving a "fail" attribute at all, seems a rather pointless complication.But I want Locale::Maketext to be usable for software projects of I<any>scale and type; and different software projects have different ideasof what the right thing is to do in failure conditions. I could simplysay that failure always throws an exception, and that if you want to becareful, you'll just have to wrap every call to $lh->maketext in anS<eval { }>. However, I want programmers to reserve the right (viathe "fail" attribute) to treat lookup failure as something other thanan exception of the same level of severity as a config file beingunreadable, or some essential resource being inaccessable.One possibly useful value for the "fail" attribute is the method name"failure_handler_auto". This is a method defined in classLocale::Maketext itself. You set it with: $lh->fail_with('failure_handler_auto');Then when you call $lh->maketext(I<key>, ...parameters...) andthere's no I<key> in any of those lexicons, maketext gives up with return $lh->failure_handler_auto($key, @params);But failure_handler_auto, instead of dying or anything, compiles$key, caching it in $lh->{'failure_lex'}{$key} = $complied,and then calls the compiled value, and returns that. (I.e., if$key looks like bracket notation, $compiled is a sub, and we return&{$compiled}(@params); but if $key is just a plain string, we justreturn that.)The effect of using "failure_auto_handler"is like an AUTO lexicon, except that it 1) compiles $key even ifit starts with "_", and 2) you have a record in the new hashref$lh->{'failure_lex'} of all the keys that have failed forthis object. This should avoid your program dying -- as longas your keys aren't actually invalid as bracket code, and aslong as they don't try calling methods that don't exist."failure_auto_handler" may not be exactly what you want, but Ihope it at least shows you that maketext failure can be mitigatedin any number of very flexible ways. If you can formalize exactlywhat you want, you should be able to express that as a failurehandler. You can even make it default for every object of a givenclass, by setting it in that class's init: sub init { my $lh = $_[0]; # a newborn handle $lh->SUPER::init(); $lh->fail_with('my_clever_failure_handler'); return; } sub my_clever_failure_handler { ...you clever things here... }=head1 HOW TO USE MAKETEXTHere is a brief checklist on how to use Maketext to localizeapplications:=over=item *Decide what system you'll use for lexicon keys. If you insist,you can use opaque IDs (if you're nostalgic for C<catgets>),but I have better suggestions in thesection "Entries in Each Lexicon", above. Assuming you opt formeaningful keys that double as values (like "Minimum ([_1]) islarger than maximum ([_2])!\n"), you'll have to settle on whatlanguage those should be in. For the sake of argument, I'llcall this English, specifically American English, "en-US".=item *Create a class for your localization project. This isthe name of the class that you'll use in the idiom: use Projname::L10N; my $lh = Projname::L10N->get_handle(...) || die "Language?";Assuming your call your class Projname::L10N, create a classconsisting minimally of: package Projname::L10N; use base qw(Locale::Maketext); ...any methods you might want all your languages to share... # And, assuming you want the base class to be an _AUTO lexicon, # as is discussed a few sections up: 1;=item *Create a class for the language your internal keys are in. Namethe class after the language-tag for that language, in lowercase,with dashes changed to underscores. Assuming your project's firstlanguage is US English, you should call this Projname::L10N::en_us.It should consist minimally of: package Projname::L10N::en_us; use base qw(Projname::L10N); %Lexicon = ( '_AUTO' => 1, ); 1;(For the rest of this section, I'll assume that this "firstlanguage class" of Projname::L10N::en_us has_AUTO lexicon.)=item *Go and write your program. Everywhere in your program where you would say: print "Foobar $thing stuff\n";instead do it thru maketext, using no variable interpolation inthe key: print $lh->maketext("Foobar [_1] stuff\n", $thing);If you get tired of constantly saying C<print $lh-E<gt>maketext>,consider making a functional wrapper for it, like so: use Projname::L10N; use vars qw($lh); $lh = Projname::L10N->get_handle(...) || die "Language?"; sub pmt (@) { print( $lh->maketext(@_)) } # "pmt" is short for "Print MakeText" $Carp::Verbose = 1; # so if maketext fails, we see made the call to pmtBesides whole phrases meant for output, anything language-dependentshould be put into the class Projname::L10N::en_us,whether as methods, or as lexicon entries -- this is discussedin the section "Entries in Each Lexicon", above.=item *Once the program is otherwise done, and once its localization forthe first language works right (via the data and methods inProjname::L10N::en_us), you can get together the data for translation.If your first language lexicon isn't an _AUTO lexicon, then you alreadyhave all the messages explicitly in the lexicon (or else you'd begetting exceptions thrown when you call $lh->maketext to getmessages that aren't in there). But if you were (advisedly) lazy and areusing an _AUTO lexicon, then you've got to make a list of all the phrasesthat you've so far been letting _AUTO generate for you. There are verymany ways to assemble such a list. The most straightforward is to simplygrep the source for every occurrence of "maketext" (or callsto wrappers around it, like the above C<pmt> function), and to log thefollowing phrase.=item *You may at this point want to consider whether the your base class (Projname::L10N) that all lexicons inherit from (Projname::L10N::en,Projname::L10N::es, etc.) should be an _AUTO lexicon. It may be truethat in theory, all needed messages will be in each language class;but in the presumably unlikely or "impossible" case of lookup failure,you should consider whether your program should throw an exception,emit text in English (or whatever your project's first language is),or some more complex solution as described in the section"Controlling Lookup Failure", above.=item *Submit all messages/phrases/etc. to translators.(You may, in fact, want to start with localizing to I<one> other languageat first, if you're not sure that you've property abstracted thelanguage-dependent parts of your code.)Translators may request clarification of the situation in which aparticular phrase is found. For example, in English we are entirely happysaying "I<n> files found", regardless of whether we mean "I looked for files,and found I<n> of them" or the rather distinct situation of "I looked forsomething else (like lines in files), and along the way I saw I<n>files." This may involve rethinking things that you thought quite clear:should "Edit" on a toolbar be a noun ("editing") or a verb ("to edit")? Isthere already a conventionalized way to express that menu option, separatefrom the target language's normal word for "to edit"?In all cases where the very common phenomenon of quantification(saying "I<N> files", for B<any> value of N)is involved, each translator should make clear what dependencies thenumber causes in the sentence. In many cases, dependency islimited to words adjacent to the number, in places where you mightexpect them ("I found the-?PLURAL I<N>empty-?PLURAL directory-?PLURAL"), but in some cases there areunexpected dependencies ("I found-?PLURAL ..."!) as well as long-distancedependencies "The I<N> directory-?PLURAL could not be deleted-?PLURAL"!).Remind the translators to consider the case where N is 0:"0 files found" isn't exactly natural-sounding in any language, but itmay be unacceptable in many -- or it may condition specialkinds of agreement (similar to English "I didN'T find ANY files").Remember to ask your translators about numeral formatting in theirlanguage, so that you can override the C<numf> method asappropriate. Typical variables in number formatting are: what touse as a decimal point (comma? period?); what to use as a thousandsseparator (space? nonbreakinng space? comma? period? smallmiddot? prime? apostrophe?); and even whether the so-called "thousandsseparator" is actually for every third digit -- I've heard reports oftwo hundred thousand being expressable as "2,00,000" for some Indian(Subcontinental) languages, besides the less surprising "S<200 000>","200.000", "200,000", and "200'000". Also, using a set of numeralglyphs other than the usual ASCII "0"-"9" might be appreciated, as viaC<tr/0-9/\x{0966}-\x{096F}/> for getting digits in Devanagari script(for Hindi, Konkani, others).The basic C<quant> method that Locale::Maketext provides should begood for many languages. For some languages, it might be usefulto modify it (or its constituent C<numerate> method)to take a plural form in the two-argument call to C<quant>(as in "[quant,_1,files]") ifit's all-around easier to infer the singular form from the plural, thanto infer the plural form from the singular.But for other languages (as is discussed at lengthin L<Locale::Maketext::TPJ13|Locale::Maketext::TPJ13>), simpleC<quant>/C<numerify> is not enough. For the particularly problematicSlavic languages, what you may need is a method which you providewith the number, the citation form of the noun to quantify, andthe case and gender that the sentence's syntax projects onto thatnoun slot. The method would then be responsible for determiningwhat grammatical number that numeral projects onto its noun phrase,and what case and gender it may override the normal case and genderwith; and then it would look up the noun in a lexicon providingall needed inflected forms.=item *You may also wish to discuss with the translators the question ofhow to relate different subforms of the same language tag,considering how this reacts with C<get_handle>'s treatment ofthese. For example, if a user accepts interfaces in "en, fr", andyou have interfaces available in "en-US" and "fr", what shouldthey get? You may wish to resolve this by establishing that "en"and "en-US" are effectively synonymous, by having one classzero-derive from the other.For some languages this issue may never come up (Danish is rarelyexpressed as "da-DK", but instead is just "da"). And for otherlanguages, the whole concept of a "generic" form may verge onbeing uselessly vague, particularly for interfaces involving voicemedia in forms of Arabic or Chinese.=item *Once you've localized your program/site/etc. for all desiredlanguages, be sure to show the result (whether live, or viascreenshots) to the translators. Once they approve, make everyeffort to have it then checked by at least one other speaker ofthat language. This holds true even when (or especially when) thetranslation is done by one of your own programmers. Somekinds of systems may be harder to find testers for than others,depending on the amount of domain-specific jargon and conceptsinvolved -- it's easier to find people who can tell you whetherthey approve of your translation for "delete this message" in anemail-via-Web interface, than to find people who can give youan informed opinion on your translation for "attribute value"in an XML query tool's interface.=back=head1 SEE ALSOI recommend reading all of these:L<Locale::Maketext::TPJ13|Locale::Maketext::TPJ13> -- my I<The PerlJournal> article about Maketext. It explains many important conceptsunderlying Locale::Maketext's design, and some insight into whyMaketext is better than the plain old approach of just having message catalogs that are just databases of sprintf formats.L<File::Findgrep|File::Findgrep> is a sample application/modulethat uses Locale::Maketext to localize its messages.L<I18N::LangTags|I18N::LangTags>.L<Win32::Locale|Win32::Locale>.RFC 3066, I<Tags for the Identification of Languages>,as at http://sunsite.dk/RFC/rfc/rfc3066.htmlRFC 2277, I<IETF Policy on Character Sets and Languages>is at http://sunsite.dk/RFC/rfc/rfc2277.html -- much of it isjust things of interest to protocol designers, but it explainssome basic concepts, like the distinction between locales andlanguage-tags.The manual for GNU C<gettext>. The gettext dist is available inC<ftp://prep.ai.mit.edu/pub/gnu/> -- geta recent gettext tarball and look in its "doc/" directory, there'san easily browsable HTML version in there. Thegettext documentation asks lots of questions worth thinkingabout, even if some of their answers are sometimes wonky,particularly where they start talking about pluralization.The Locale/Maketext.pm source. Obverse that the module is muchshorter than its documentation!=head1 COPYRIGHT AND DISCLAIMERCopyright (c) 1999-2001 Sean M. Burke. All rights reserved.This library is free software; you can redistribute it and/or modifyit under the same terms as Perl itself.This program is distributed in the hope that it will be useful, butwithout any warranty; without even the implied warranty ofmerchantability or fitness for a particular purpose.=head1 AUTHORSean M. Burke C<sburke@cpan.org>=cut# Zing!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -