📄 locale::maketext.3
字号:
these are not phrases for output)..PPOr 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 in a method in the language class. (Thatleaves a tidy distinction between the lexicon as the things weknow how to \fIsay\fR, and the rest of the things in the lexicon classas things that we know how to \fIdo\fR.) Considerthis example of a processor for responses to French \*(L"oui/non\*(R"questions:.PP.Vb 7\& sub y_or_n {\& return undef unless defined $_[1] and length $_[1];\& my $answer = lc $_[1]; # smash case\& return 1 if $answer eq \*(Aqo\*(Aq or $answer eq \*(Aqoui\*(Aq;\& return 0 if $answer eq \*(Aqn\*(Aq or $answer eq \*(Aqnon\*(Aq;\& return undef;\& }.Ve.PP\&...which you'd then call in a construct like this:.PP.Vb 7\& 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() }.Ve.PPOther data worth storing in a lexicon might be things likefilenames for language-targetted resources:.PP.Vb 10\& ...\& "_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.\& ....Ve.PPYou might want to do the same thing for expressing key bindingsor the like (since hardwiring \*(L"q\*(R" as the binding for the functionthat quits a screen/menu/program is useful only if your languagehappens to associate \*(L"q\*(R" with \*(L"quit\*(R"!).SH "BRACKET NOTATION".IX Header "BRACKET NOTATION"Bracket Notation is a crucial feature of Locale::Maketext. I meanBracket Notation to provide a replacement for the use of 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..PPBracket Notation is a like a miniature \*(L"template\*(R" system (in the senseof Text::Template, not in the sense of \*(C+ templates),where normal text is passed thru basically as is, but text in specialregions is specially interpreted. In Bracket Notation, you use square brackets (\*(L"[...]\*(R"),not curly braces (\*(L"{...}\*(R") to note sections that are specially interpreted..PPFor example, here all the areas that are taken literally are underlined witha \*(L"^\*(R", and all the in-bracket special regions are underlined with an X:.PP.Vb 2\& "Minimum ([_1]) is larger than maximum ([_2])!\en",\& ^^^^^^^^^ XX ^^^^^^^^^^^^^^^^^^^^^^^^^^ XX ^^^^.Ve.PPWhen that string is compiled from bracket notation into a real Perl sub,it's basically turned into:.PP.Vb 11\& sub {\& my $lh = $_[0];\& my @params = @_;\& return join \*(Aq\*(Aq,\& "Minimum (",\& ...some code here...\& ") is larger than maximum (",\& ...some code here...\& ")!\en",\& }\& # to be called by $lh\->maketext(KEY, params...).Ve.PPIn other words, text outside bracket groups is turned into stringliterals. Text in brackets is rather more complex, and currently followsthese rules:.IP "\(bu" 4Bracket groups that are empty, or which consist only of whitespace,are ignored. (Examples: \*(L"[]\*(R", \*(L"[ ]\*(R", or a [ and a ] with returnsand/or tabs and/or spaces between them..SpOtherwise, each group is taken to be a comma-separated group of items,and each item is interpreted as follows:.IP "\(bu" 4An item that is "_\fIdigits\fR\*(L" or \*(R"_\-\fIdigits\fR" is interpreted as\&\f(CW$_\fR[\fIvalue\fR]. I.e., \*(L"_1\*(R" becomes with \f(CW$_\fR[1], and \*(L"_\-3\*(R" is interpretedas \f(CW$_\fR[\-3] (in which case \f(CW@_\fR should have at least three elements in it).Note that \f(CW$_\fR[0] is the language handle, and is typically not nameddirectly..IP "\(bu" 4An item \*(L"_*\*(R" is interpreted to mean \*(L"all of \f(CW@_\fR except \f(CW$_\fR[0]\*(R".I.e., \f(CW@_[1..$#_]\fR. Note that this is an empty list in the caseof calls like \f(CW$lh\fR\->maketext(\fIkey\fR) where there are noparameters (except \f(CW$_\fR[0], the language handle)..IP "\(bu" 4Otherwise, each item is interpreted as a string literal..PPThe group as a whole is interpreted as follows:.IP "\(bu" 4If the first item in a bracket group looks like a method name,then that group is interpreted like this:.Sp.Vb 3\& $lh\->that_method_name(\& ...rest of items in this group...\& ),.Ve.IP "\(bu" 4If the first item in a bracket group is \*(L"*\*(R", it's taken as shorthandfor the so commonly called \*(L"quant\*(R" method. Similarly, if the firstitem in a bracket group is \*(L"#\*(R", it's taken to be shorthand for\&\*(L"numf\*(R"..IP "\(bu" 4If the first item in a bracket group is the empty-string, or \*(L"_*\*(R"or "_\fIdigits\fR\*(L" or \*(R"_\-\fIdigits\fR", then that group is interpretedas just the interpolation of all its items:.Sp.Vb 3\& join(\*(Aq\*(Aq,\& ...rest of items in this group...\& ),.Ve.SpExamples: \*(L"[_1]\*(R" and \*(L"[,_1]\*(R", which are synonymous; and"\f(CW\*(C`[,ID\-(,_4,\-,_2,)]\*(C'\fR", which compiles as\&\f(CW\*(C`join "", "ID\-(", $_[4], "\-", $_[2], ")"\*(C'\fR..IP "\(bu" 4Otherwise this bracket group is invalid. For example, in the group\&\*(L"[!@#,whatever]\*(R", the first item \f(CW"!@#"\fR is neither the empty-string,"_\fInumber\fR\*(L", \*(R"_\-\fInumber\fR\*(L", \*(R"_*", nor a valid method name; and soLocale::Maketext will throw an exception of you try compiling anexpression containing this bracket group..PPNote, incidentally, that items in each group are comma-separated,not \f(CW\*(C`/\es*,\es*/\*(C'\fR\-separated. That is, you might expect that thisbracket group:.PP.Vb 1\& "Hoohah [foo, _1 , bar ,baz]!".Ve.PPwould compile to this:.PP.Vb 7\& sub {\& my $lh = $_[0];\& return join \*(Aq\*(Aq,\& "Hoohah ",\& $lh\->foo( $_[1], "bar", "baz"),\& "!",\& }.Ve.PPBut it actually compiles as this:.PP.Vb 7\& sub {\& my $lh = $_[0];\& return join \*(Aq\*(Aq,\& "Hoohah ",\& $lh\->foo(" _1 ", " bar ", "baz"), # note the <space> in " bar "\& "!",\& }.Ve.PPIn the notation discussed so far, the characters \*(L"[\*(R" and \*(L"]\*(R" are givenspecial meaning, for opening and closing bracket groups, and \*(L",\*(R" hasa special meaning inside bracket groups, where it separates items in thegroup. This begs the question of how you'd express a literal \*(L"[\*(R" or\&\*(L"]\*(R" in a Bracket Notation string, and how you'd express a literalcomma inside a bracket group. For this purpose I've adopted \*(L"~\*(R" (tilde)as an escape character: \*(L"~[\*(R" means a literal '[' character anywherein Bracket Notation (i.e., regardless of whether you're in a bracketgroup or not), and ditto for \*(L"~]\*(R" meaning a literal ']', and \*(L"~,\*(R" meaninga literal comma. (Altho \*(L",\*(R" means a literal comma outside ofbracket groups \*(-- it's only inside bracket groups that commas are special.).PPAnd on the off chance you need a literal tilde in a bracket expression,you get it with \*(L"~~\*(R"..PPCurrently, an unescaped \*(L"~\*(R" before a characterother than a bracket or a comma is taken to mean just a \*(L"~\*(R" and thatcharacter. I.e., \*(L"~X\*(R" means the same as \*(L"~~X\*(R" \*(-- i.e., one literal tilde,and then one literal \*(L"X\*(R". However, by using \*(L"~X\*(R", you are assuming thatno future version of Maketext will use \*(L"~X\*(R" as a magic escape sequence.In practice this is not a great problem, since first off you can justwrite \*(L"~~X\*(R" and not worry about it; second off, I doubt I'll add lotsof new magic characters to bracket notation; and third off, youaren't likely to want literal \*(L"~\*(R" characters in your messages anyway,since it's not a character with wide use in natural language text..PPBrackets must be balanced \*(-- every openbracket must haveone matching closebracket, and vice versa. So these are all \fBinvalid\fR:.PP.Vb 4\& "I ate [quant,_1,rhubarb pie."\& "I ate [quant,_1,rhubarb pie[."\& "I ate quant,_1,rhubarb pie]."\& "I ate quant,_1,rhubarb pie[.".Ve.PPCurrently, bracket groups do not nest. That is, you \fBcannot\fR say:.PP.Vb 1\& "Foo [bar,baz,[quux,quuux]]\en";.Ve.PPIf you need a notation that's that powerful, use normal Perl:.PP.Vb 11\& %Lexicon = (\& ...\& "some_key" => sub {\& my $lh = $_[0];\& join \*(Aq\*(Aq,\& "Foo ",\& $lh\->bar(\*(Aqbaz\*(Aq, $lh\->quux(\*(Aqquuux\*(Aq)),\& "\en",\& },\& ...\& );.Ve.PPOr write the \*(L"bar\*(R" method so you don't need to pass it theoutput from calling quux..PPI do not anticipate that you will need (or particularly want)to nest bracket groups, but you are welcome to email me withconvincing (real-life) arguments to the contrary..SH "AUTO LEXICONS".IX Header "AUTO LEXICONS"If maketext goes to look in an individual \f(CW%Lexicon\fR for an entryfor \fIkey\fR (where \fIkey\fR does not start with an underscore), andsees none, \fBbut does see\fR an entry of \*(L"_AUTO\*(R" => \fIsome_true_value\fR,then we actually define \f(CW$Lexicon\fR{\fIkey\fR} = \fIkey\fR right then and there,and then use that value as if it had been there allalong. This happens before we even look in any superclass \f(CW%Lexicons\fR!.PP(This is meant to be somewhat like the \s-1AUTOLOAD\s0 mechanism inPerl's function call system \*(-- or, looked at another way,like the AutoLoader module.).PPI can picture all sorts of circumstances where you justdo not want lookup to be able to fail (since failingnormally means that maketext throws a \f(CW\*(C`die\*(C'\fR, althoughsee the next section for greater control over that). Buthere's one circumstance where _AUTO lexicons are meant tobe \fIespecially\fR useful:.PPAs you're writing an application, you decide as you go what messagesyou need to emit. Normally you'd go to write this:.PP.Vb 5\& if(\-e $filename) {\& go_process_file($filename)\& } else {\& print qq{Couldn\*(Aqt find file "$filename"!\en};\& }.Ve.PPbut since you anticipate localizing this, you write:.PP.Vb 10\& use ThisProject::I18N;\& my $lh = ThisProject::I18N\->get_handle();\& # For the moment, assume that things are set up so\& # that we load class ThisProject::I18N::en\& # and that that\*(Aqs the class that $lh belongs to.\& ...\& if(\-e $filename) {\& go_process_file($filename)\& } else {\& print $lh\->maketext(\& qq{Couldn\*(Aqt find file "[_1]"!\en}, $filename\& );\& }.Ve.PPNow, right after you've just written the above lines, you'dnormally have to go open the file ThisProject/I18N/en.pm, and immediately add an entry:.PP.Vb 2\& "Couldn\*(Aqt find file \e"[_1]\e"!\en"\& => "Couldn\*(Aqt find file \e"[_1]\e"!\en",.Ve.PPBut I consider that somewhat of a distraction from the workof getting the main code working \*(-- to say nothing of the factthat I often have to play with the program a few times beforeI can decide exactly what wording I want in the messages (whichin this case would require me to go changing three lines of code:the call to maketext with that key, and then the two lines inThisProject/I18N/en.pm)..PPHowever, if you set \*(L"_AUTO => 1\*(R" in the \f(CW%Lexicon\fR in,ThisProject/I18N/en.pm (assuming that English (en) isthe language that all your programmers will be using for thisproject's internal message keys), then you don't ever have togo adding lines like this.PP.Vb 2\& "Couldn\*(Aqt find file \e"[_1]\e"!\en"\& => "Couldn\*(Aqt find file \e"[_1]\e"!\en",.Ve.PPto ThisProject/I18N/en.pm, because if _AUTO is true there,then just looking for an entry with the key \*(L"Couldn't findfile \e\*(R"[_1]\e\*(L"!\en\*(R" in that lexicon will cause it to be added,with that value!.PPNote that the reason that keys that start with \*(L"_\*(R"are immune to _AUTO isn't anything generally magical aboutthe underscore character \*(-- I just wanted a way to have mostlexicon keys be autoable, except for possibly a few, and Iarbitrarily decided to use a leading underscore as a signalto distinguish those few..SH "CONTROLLING LOOKUP FAILURE".IX Header "CONTROLLING LOOKUP FAILURE"If you call \f(CW$lh\fR\->maketext(\fIkey\fR, ...parameters...),and there's no entry \fIkey\fR in \f(CW$lh\fR's class's \f(CW%Lexicon\fR, norin the superclass \f(CW%Lexicon\fR hash, \fIand\fR if we can't auto-make\&\fIkey\fR (because either it starts with a \*(L"_\*(R", or because noneof its lexicons have \f(CW\*(C`_AUTO => 1,\*(C'\fR), then we havefailed to find a normal way to maketext \fIkey\fR. What thenhappens in these failure conditions, depends on the \f(CW$lh\fR object's\&\*(L"fail\*(R" attribute..PPIf the language handle has no \*(L"fail\*(R" attribute, maketextwill simply throw an exception (i.e., it calls \f(CW\*(C`die\*(C'\fR, mentioningthe \fIkey\fR whose lookup failed, and naming the line number wherethe calling \f(CW$lh\fR\->maketext(\fIkey\fR,...) was..PPIf the language handle has a \*(L"fail\*(R" attribute whose value is acoderef, then \f(CW$lh\fR\->maketext(\fIkey\fR,...params...) gives up and calls:.PP.Vb 1\& return $that_subref\->($lh, $key, @params);.Ve.PPOtherwise, the \*(L"fail\*(R" attribute's value should be a string denotinga method name, so that \f(CW$lh\fR\->maketext(\fIkey\fR,...params...) can
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -