⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 locale::maketext.3

📁 视频监控网络部分的协议ddns,的模块的实现代码,请大家大胆指正.
💻 3
📖 第 1 页 / 共 4 页
字号:
give up with:.PP.Vb 1\&  return $lh\->$that_method_name($phrase, @params);.Ve.PPThe \*(L"fail\*(R" attribute can be accessed with the \f(CW\*(C`fail_with\*(C'\fR method:.PP.Vb 2\&  # Set to a coderef:\&  $lh\->fail_with( \e&failure_handler );\&\&  # Set to a method name:\&  $lh\->fail_with( \*(Aqfailure_method\*(Aq );\&  \&  # Set to nothing (i.e., so failure throws a plain exception)\&  $lh\->fail_with( undef );\&  \&  # Get the current value\&  $handler = $lh\->fail_with();.Ve.PPNow, as to what you may want to do with these handlers:  Maybe you'dwant to log what key failed for what class, and then die.  Maybeyou don't like \f(CW\*(C`die\*(C'\fR and instead you want to send the error messageto \s-1STDOUT\s0 (or wherever) and then merely \f(CW\*(C`exit()\*(C'\fR..PPOr maybe you don't want to \f(CW\*(C`die\*(C'\fR at all!  Maybe you could use ahandler like this:.PP.Vb 10\&  # Make all lookups fall back onto an English value,\&  #  but only after we log it for later fingerpointing.\&  my $lh_backup = ThisProject\->get_handle(\*(Aqen\*(Aq);\&  open(LEX_FAIL_LOG, ">>wherever/lex.log") || die "GNAARGH $!";\&  sub lex_fail {\&    my($failing_lh, $key, $params) = @_;\&    print LEX_FAIL_LOG scalar(localtime), "\et",\&       ref($failing_lh), "\et", $key, "\en";\&    return $lh_backup\->maketext($key,@params);\&  }.Ve.PPSome users have expressed that they think this whole mechanism ofhaving a \*(L"fail\*(R" attribute at all, seems a rather pointless complication.But I want Locale::Maketext to be usable for software projects of \fIany\fRscale 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 \f(CW$lh\fR\->maketext in aneval\ {\ }.  However, I want programmers to reserve the right (viathe \*(L"fail\*(R" 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 inaccessible..PPOne possibly useful value for the \*(L"fail\*(R" attribute is the method name\&\*(L"failure_handler_auto\*(R".  This is a method defined in the classLocale::Maketext itself.  You set it with:.PP.Vb 1\&  $lh\->fail_with(\*(Aqfailure_handler_auto\*(Aq);.Ve.PPThen when you call \f(CW$lh\fR\->maketext(\fIkey\fR, ...parameters...) andthere's no \fIkey\fR in any of those lexicons, maketext gives up with.PP.Vb 1\&  return $lh\->failure_handler_auto($key, @params);.Ve.PPBut failure_handler_auto, instead of dying or anything, compiles\&\f(CW$key\fR, caching it in.PP.Vb 1\&    $lh\->{\*(Aqfailure_lex\*(Aq}{$key} = $complied.Ve.PPand then calls the compiled value, and returns that.  (I.e., if\&\f(CW$key\fR looks like bracket notation, \f(CW$compiled\fR is a sub, and we return&{$compiled}(@params); but if \f(CW$key\fR is just a plain string, we justreturn that.).PPThe effect of using \*(L"failure_auto_handler\*(R"is like an \s-1AUTO\s0 lexicon, except that it 1) compiles \f(CW$key\fR even ifit starts with \*(L"_\*(R", and 2) you have a record in the new hashref\&\f(CW$lh\fR\->{'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..PP\&\*(L"failure_auto_handler\*(R" 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:.PP.Vb 9\&  sub init {\&    my $lh = $_[0];  # a newborn handle\&    $lh\->SUPER::init();\&    $lh\->fail_with(\*(Aqmy_clever_failure_handler\*(Aq);\&    return;\&  }\&  sub my_clever_failure_handler {\&    ...you clever things here...\&  }.Ve.SH "HOW TO USE MAKETEXT".IX Header "HOW TO USE MAKETEXT"Here is a brief checklist on how to use Maketext to localizeapplications:.IP "\(bu" 4Decide what system you'll use for lexicon keys.  If you insist,you can use opaque IDs (if you're nostalgic for \f(CW\*(C`catgets\*(C'\fR),but I have better suggestions in thesection \*(L"Entries in Each Lexicon\*(R", above.  Assuming you opt formeaningful keys that double as values (like \*(L"Minimum ([_1]) islarger than maximum ([_2])!\en\*(R"), you'll have to settle on whatlanguage those should be in.  For the sake of argument, I'llcall this English, specifically American English, \*(L"en-US\*(R"..IP "\(bu" 4Create a class for your localization project.  This isthe name of the class that you'll use in the idiom:.Sp.Vb 2\&  use Projname::L10N;\&  my $lh = Projname::L10N\->get_handle(...) || die "Language?";.Ve.SpAssuming you call your class Projname::L10N, create a classconsisting minimally of:.Sp.Vb 3\&  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;.Ve.IP "\(bu" 4Create 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 \s-1US\s0 English, you should call this Projname::L10N::en_us.It should consist minimally of:.Sp.Vb 6\&  package Projname::L10N::en_us;\&  use base qw(Projname::L10N);\&  %Lexicon = (\&    \*(Aq_AUTO\*(Aq => 1,\&  );\&  1;.Ve.Sp(For the rest of this section, I'll assume that this \*(L"firstlanguage class\*(R" of Projname::L10N::en_us has_AUTO lexicon.).IP "\(bu" 4Go and write your program.  Everywhere in your program where you would say:.Sp.Vb 1\&  print "Foobar $thing stuff\en";.Ve.Spinstead do it thru maketext, using no variable interpolation inthe key:.Sp.Vb 1\&  print $lh\->maketext("Foobar [_1] stuff\en", $thing);.Ve.SpIf you get tired of constantly saying \f(CW\*(C`print $lh\->maketext\*(C'\fR,consider making a functional wrapper for it, like so:.Sp.Vb 7\&  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 pmt.Ve.SpBesides 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 \*(L"Entries in Each Lexicon\*(R", above..IP "\(bu" 4Once 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 \f(CW$lh\fR\->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 \*(L"maketext\*(R" (or callsto wrappers around it, like the above \f(CW\*(C`pmt\*(C'\fR function), and to log thefollowing phrase..IP "\(bu" 4You may at this point want to consider whether your base class (Projname::L10N), from which 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 \*(L"impossible\*(R" 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\&\*(L"Controlling Lookup Failure\*(R", above..IP "\(bu" 4Submit all messages/phrases/etc. to translators..Sp(You may, in fact, want to start with localizing to \fIone\fR other languageat first, if you're not sure that you've properly abstracted thelanguage-dependent parts of your code.).SpTranslators may request clarification of the situation in which aparticular phrase is found.  For example, in English we are entirely happysaying "\fIn\fR files found\*(L", regardless of whether we mean \*(R"I looked for files,and found \fIn\fR of them\*(L" or the rather distinct situation of \*(R"I looked forsomething else (like lines in files), and along the way I saw \fIn\fRfiles.\*(L"  This may involve rethinking things that you thought quite clear:should \*(R"Edit\*(L" on a toolbar be a noun (\*(R"editing\*(L") or a verb (\*(R"to edit\*(L")?  Isthere already a conventionalized way to express that menu option, separatefrom the target language's normal word for \*(R"to edit"?.SpIn all cases where the very common phenomenon of quantification(saying "\fIN\fR files", for \fBany\fR 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 \fIN\fRempty\-?PLURAL directory\-?PLURAL\*(L"), but in some cases there areunexpected dependencies (\*(R"I found\-?PLURAL ...\*(L"!) as well as long-distancedependencies \*(R"The \fIN\fR directory\-?PLURAL could not be deleted\-?PLURAL"!)..SpRemind the translators to consider the case where N is 0:\&\*(L"0 files found\*(R" isn't exactly natural-sounding in any language, but itmay be unacceptable in many \*(-- or it may condition specialkinds of agreement (similar to English \*(L"I didN'T find \s-1ANY\s0 files\*(R")..SpRemember to ask your translators about numeral formatting in theirlanguage, so that you can override the \f(CW\*(C`numf\*(C'\fR method asappropriate.  Typical variables in number formatting are:  what touse as a decimal point (comma? period?); what to use as a thousandsseparator (space? nonbreaking space? comma? period? smallmiddot? prime? apostrophe?); and even whether the so-called \*(L"thousandsseparator\*(R" is actually for every third digit \*(-- I've heard reports oftwo hundred thousand being expressible as \*(L"2,00,000\*(R" for some Indian(Subcontinental) languages, besides the less surprising \*(L"200\ 000\*(R",\&\*(L"200.000\*(R", \*(L"200,000\*(R", and \*(L"200'000\*(R".  Also, using a set of numeralglyphs other than the usual \s-1ASCII\s0 \*(L"0\*(R"\-\*(L"9\*(R" might be appreciated, as via\&\f(CW\*(C`tr/0\-9/\ex{0966}\-\ex{096F}/\*(C'\fR for getting digits in Devanagari script(for Hindi, Konkani, others)..SpThe basic \f(CW\*(C`quant\*(C'\fR method that Locale::Maketext provides should begood for many languages.  For some languages, it might be usefulto modify it (or its constituent \f(CW\*(C`numerate\*(C'\fR method)to take a plural form in the two-argument call to \f(CW\*(C`quant\*(C'\fR(as in \*(L"[quant,_1,files]\*(R") ifit's all-around easier to infer the singular form from the plural, thanto infer the plural form from the singular..SpBut for other languages (as is discussed at lengthin Locale::Maketext::TPJ13), simple\&\f(CW\*(C`quant\*(C'\fR/\f(CW\*(C`numerify\*(C'\fR 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..IP "\(bu" 4You 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 \f(CW\*(C`get_handle\*(C'\fR's treatment ofthese.  For example, if a user accepts interfaces in \*(L"en, fr\*(R", andyou have interfaces available in \*(L"en-US\*(R" and \*(L"fr\*(R", what shouldthey get?  You may wish to resolve this by establishing that \*(L"en\*(R"and \*(L"en-US\*(R" are effectively synonymous, by having one classzero-derive from the other..SpFor some languages this issue may never come up (Danish is rarelyexpressed as \*(L"da-DK\*(R", but instead is just \*(L"da\*(R").  And for otherlanguages, the whole concept of a \*(L"generic\*(R" form may verge onbeing uselessly vague, particularly for interfaces involving voicemedia in forms of Arabic or Chinese..IP "\(bu" 4Once 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 \*(L"delete this message\*(R" in anemail-via-Web interface, than to find people who can give youan informed opinion on your translation for \*(L"attribute value\*(R"in an \s-1XML\s0 query tool's interface..SH "SEE ALSO".IX Header "SEE ALSO"I recommend reading all of these:.PPLocale::Maketext::TPJ13 \*(-- my \fIThe PerlJournal\fR 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 having message catalogs that are just databases of sprintf formats..PPFile::Findgrep is a sample application/modulethat uses Locale::Maketext to localize its messages.  For a largerinternationalized system, see also Apache::MP3..PPI18N::LangTags..PPWin32::Locale..PP\&\s-1RFC\s0 3066, \fITags for the Identification of Languages\fR,as at http://sunsite.dk/RFC/rfc/rfc3066.html.PP\&\s-1RFC\s0 2277, \fI\s-1IETF\s0 Policy on Character Sets and Languages\fRis 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..PPThe manual for \s-1GNU\s0 \f(CW\*(C`gettext\*(C'\fR.  The gettext dist is available in\&\f(CW\*(C`ftp://prep.ai.mit.edu/pub/gnu/\*(C'\fR \*(-- geta recent gettext tarball and look in its \*(L"doc/\*(R" directory, there'san easily browsable \s-1HTML\s0 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..PPThe Locale/Maketext.pm source.  Obverse that the module is muchshorter than its documentation!.SH "COPYRIGHT AND DISCLAIMER".IX Header "COPYRIGHT AND DISCLAIMER"Copyright (c) 1999\-2004 Sean M. Burke.  All rights reserved..PPThis library is free software; you can redistribute it and/or modifyit under the same terms as Perl itself..PPThis 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..SH "AUTHOR".IX Header "AUTHOR"Sean M. Burke \f(CW\*(C`sburke@cpan.org\*(C'\fR

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -