📄 maketext.pod
字号:
as this pseudocode describes: if $number is 0 and there's a $negative, return $negative; elsif $number is 1, return "1 $singular"; elsif there's a $plural, return "$number $plural"; else return "$number " . $singular . "s"; # # ...except that we actually call numf to # stringify $number before returning it.So for English (with Bracket Notation)C<"...[quant,_1,file]..."> is fine (for 0 it returns "0 files",for 1 it returns "1 file", and for more it returns "2 files", etc.)But for "directory", you'd want C<"[quant,_1,direcory,directories]">so that our elementary C<quant> method doesn't think that theplural of "directory" is "directorys". And you might find that theoutput may sound better if you specify a negative form, as in: "[quant,_1,file,files,No files] matched your query.\n"Remember to keep in mind verb agreement (or adjectives too, inother languages), as in: "[quant,_1,document] were matched.\n"Because if _1 is one, you get "1 document B<were> matched".An acceptable hack here is to do something like this: "[quant,_1,document was, documents were] matched.\n"=item $language->numf($number)This returns the given number formatted nicely according tothis language's conventions. Maketext's default method ismostly to just take the normal string form of the number(applying sprintf "%G" for only very large numbers), and thento add commas as necessary. (Except thatwe apply C<tr/,./.,/> if $language->{'numf_comma'} is true;that's a bit of a hack that's useful for languages that expresstwo million as "2.000.000" and not as "2,000,000").If you want anything fancier, consider overriding this with somethingthat uses L<Number::Format|Number::Format>, or does something elseentirely.Note that numf is called by quant for stringifying all quantifyingnumbers.=item $language->sprintf($format, @items)This is just a wrapper around Perl's normal C<sprintf> function.It's provided so that you can use "sprintf" in Bracket Notation: "Couldn't access datanode [sprintf,%10x=~[%s~],_1,_2]!\n"returning... Couldn't access datanode Stuff=[thangamabob]!=item $language->language_tag()Currently this just takes the last bit of C<ref($language)>, turnsunderscores to dashes, and returns it. So if $language isan object of class Hee::HOO::Haw::en_us, $language->language_tag()returns "en-us". (Yes, the usual representation for that languagetag is "en-US", but case is I<never> considered meaningful inlanguage-tag comparison.)You may override this as you like; Maketext doesn't use it foranything.=item $language->encoding()Currently this isn't used for anything, but it's provided(with default value ofC<(ref($language) && $language-E<gt>{'encoding'})) or "iso-8859-1">) as a sort of suggestion that it may be useful/necessary toassociate encodings with your language handles (whether on aper-class or even per-handle basis.)=back=head2 Language Handle Attributes and InternalsA language handle is a flyweight object -- i.e., it doesn't (necessarily)carry any data of interest, other than just being a member ofwhatever class it belongs to.A language handle is implemented as a blessed hash. Subclasses of yourscan store whatever data you want in the hash. Currently the only hashentry used by any crucial Maketext method is "fail", so feel free touse anything else as you like.B<Remember: Don't be afraid to read the Maketext source if there'sany point on which this documentation is unclear.> This documentationis vastly longer than the module source itself.=over=back=head1 LANGUAGE CLASS HIERARCHIESThese are Locale::Maketext's assumptions about the classhierarchy formed by all your language classes:=over=item *You must have a project base class, which you load, andwhich you then use as the first argument inthe call to YourProjClass->get_handle(...). It should derive(whether directly or indirectly) from Locale::Maketext.It B<doesn't matter> how you name this class, altho assuming thisis the localization component of your Super Mega Program,good names for your project class might beSuperMegaProgram::Localization, SuperMegaProgram::L10N,SuperMegaProgram::I18N, SuperMegaProgram::International,or even SuperMegaProgram::Languages or SuperMegaProgram::Messages.=item *Language classes are what YourProjClass->get_handle will try to load.It will look for them by taking each language-tag (B<skipping> itif it doesn't look like a language-tag or locale-tag!), turning it toall lowercase, turning and dashes to underscores, and appending itto YourProjClass . "::". So this: $lh = YourProjClass->get_handle( 'en-US', 'fr', 'kon', 'i-klingon', 'i-klingon-romanized' );will try loading the classes YourProjClass::en_us (note lowercase!), YourProjClass::fr, YourProjClass::kon,YourProjClass::i_klingonand YourProjClass::i_klingon_romanized. (And it'll stop at thefirst one that actually loads.)=item *I assume that each language class derives (directly or indirectly)from your project class, and also defines its @ISA, its %Lexicon,or both. But I anticipate no dire consequences if these assumptionsdo not hold.=item *Language classes may derive from other language classes (altho theyshould have "use I<Thatclassname>" or "use base qw(I<...classes...>)").They may derive from the projectclass. They may derive from some other class altogether. Or viamultiple inheritance, it may derive from any mixture of these.=item *I foresee no problems with having multiple inheritance inyour hierarchy of language classes. (As usual, however, Perl willcomplain bitterly if you have a cycle in the hierarchy: i.e., ifany class is its own ancestor.)=back=head1 ENTRIES IN EACH LEXICONA typical %Lexicon entry is meant to signify a phrase,taking some number (0 or more) of parameters. An entryis meant to be accessed by viaa string I<key> in $lh->maketext(I<key>, ...parameters...),which should return a string that is generally meant forbe used for "output" to the user -- regardless of whetherthis actually means printing to STDOUT, writing to a file,or putting into a GUI widget.While the key must be a string value (since that's a basicrestriction that Perl places on hash keys), the value inthe lexicon can currenly be of several types:a defined scalar, scalarref, or coderef. The use of these isexplained above, in the section 'The "maketext" Method', andBracket Notation for strings is discussed in the next section.While you can use arbitrary unique IDs for lexicon keys(like "_min_larger_max_error"), it is oftenuseful for if an entry's key is itself a valid value, likethis example error message: "Minimum ([_1]) is larger than maximum ([_2])!\n",Compare this code that uses an arbitrary ID... die $lh->maketext( "_min_larger_max_error", $min, $max ) if $min > $max;...to this code that uses a key-as-value: die $lh->maketext( "Minimum ([_1]) is larger than maximum ([_2])!\n", $min, $max ) if $min > $max;The second is, in short, more readable. In particular, it's obviousthat the number of parameters you're feeding to that phrase (two) isthe number of parameters that it I<wants> to be fed. (Since you see_1 and a _2 being used in the key there.)Also, once a project is otherwisecomplete and you start to localize it, you can scrape togetherall the various keys you use, and pass it to a translator; and thenthe translator's work will go faster if what he's presented is this: "Minimum ([_1]) is larger than maximum ([_2])!\n", => "", # fill in something here, Jacques!rather than this more cryptic mess: "_min_larger_max_error" => "", # fill in something here, JacquesI think that keys as lexicon values makes the completed lexiconentries more readable: "Minimum ([_1]) is larger than maximum ([_2])!\n", => "Le minimum ([_1]) est plus grand que le maximum ([_2])!\n",Also, having valid values as keys becomes very useful if you setup an _AUTO lexicon. _AUTO lexicons are discussed in a latersection.I almost always use keys that are themselvesvalid lexicon values. One notable exception is when the value isquite long. For example, to get the screenful of data thata command-line program might returns when given an unknown switch,I often just use a key "_USAGE_MESSAGE". At that point I then goand immediately to define that lexicon entry in theProjectClass::L10N::en lexicon (since English is always my "projectlanuage"): '_USAGE_MESSAGE' => <<'EOSTUFF', ...long long message... EOSTUFFand then I can use it as: getopt('oDI', \%opts) or die $lh->maketext('_USAGE_MESSAGE');Incidentally,note that each class's C<%Lexicon> inherits-and-extendsthe lexicons in its superclasses. This is not because these arespecial hashes I<per se>, but because you access them via theC<maketext> method, which looks for entries across all theC<%Lexicon>'s in a language class I<and> all its ancestor classes.(This is because the idea of "class data" isn't directly implementedin Perl, but is instead left to individual class-systems to implementas they see fit..)Note that you may have things stored in a lexiconbesides just phrases for output: for example, if your programtakes input from the keyboard, asking a "(Y/N)" question,you probably need to know what equivalent of "Y[es]/N[o]" isin whatever language. You probably also need to know whatthe equivalents of the answers "y" and "n" are. You canstore that information in the lexicon (say, under the keys"~answer_y" and "~answer_n", and the long forms as"~answer_yes" and "~answer_no", where "~" is just an ad-hoccharacter meant to indicate to programmers/translators thatthese are not phrases for output).Or instead of storing this in the language class's lexicon,you can (and, in some cases, really should) represent the same bitof knowledge as code is a method in the language class. (Thatleaves a tidy distinction between the lexicon as the things weknow how to I<say>, and the rest of the things in the lexicon classas things that we know how to I<do>.) Considerthis example of a processor for responses to French "oui/non"questions: sub y_or_n { return undef unless defined $_[1] and length $_[1]; my $answer = lc $_[1]; # smash case return 1 if $answer eq 'o' or $answer eq 'oui'; return 0 if $answer eq 'n' or $answer eq 'non'; return undef; }...which you'd then call in a construct like this: my $response; until(defined $response) { print $lh->maketext("Open the pod bay door (y/n)? "); $response = $lh->y_or_n( get_input_from_keyboard_somehow() ); } if($response) { $pod_bay_door->open() } else { $pod_bay_door->leave_closed() }Other data worth storing in a lexicon might be things likefilenames for language-targetted resources: ... "_main_splash_png" => "/styles/en_us/main_splash.png", "_main_splash_imagemap" => "/styles/en_us/main_splash.incl", "_general_graphics_path" => "/styles/en_us/", "_alert_sound" => "/styles/en_us/hey_there.wav", "_forward_icon" => "left_arrow.png", "_backward_icon" => "right_arrow.png", # In some other languages, left equals # BACKwards, and right is FOREwards. ...You might want to do the same thing for expressing key bindingsor the like (since hardwiring "q" as the binding for the functionthat quits a screen/menu/program is useful only if your languagehappens to associate "q" with "quit"!)=head1 BRACKET NOTATIONBracket Notation is a crucial feature of Locale::Maketext. I meanBracket Notation to provide a replacement for sprintf formatting.Everything you do with Bracket Notation could be done with a sub block,but bracket notation is meant to be much more concise.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -