Initialized from version 1.28 (2009/6/27).
This commit is contained in:
commit
db7e22c83b
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
Makefile
|
||||
Makefile.old
|
||||
blib
|
||||
Build
|
||||
_build
|
||||
MYMETA.json
|
||||
MYMETA.yml
|
||||
pm_to_blib
|
131
Artistic
Normal file
131
Artistic
Normal file
@ -0,0 +1,131 @@
|
||||
|
||||
|
||||
|
||||
|
||||
The "Artistic License"
|
||||
|
||||
Preamble
|
||||
|
||||
The intent of this document is to state the conditions under which a
|
||||
Package may be copied, such that the Copyright Holder maintains some
|
||||
semblance of artistic control over the development of the package,
|
||||
while giving the users of the package the right to use and distribute
|
||||
the Package in a more-or-less customary fashion, plus the right to make
|
||||
reasonable modifications.
|
||||
|
||||
Definitions:
|
||||
|
||||
"Package" refers to the collection of files distributed by the
|
||||
Copyright Holder, and derivatives of that collection of files
|
||||
created through textual modification.
|
||||
|
||||
"Standard Version" refers to such a Package if it has not been
|
||||
modified, or has been modified in accordance with the wishes
|
||||
of the Copyright Holder as specified below.
|
||||
|
||||
"Copyright Holder" is whoever is named in the copyright or
|
||||
copyrights for the package.
|
||||
|
||||
"You" is you, if you're thinking about copying or distributing
|
||||
this Package.
|
||||
|
||||
"Reasonable copying fee" is whatever you can justify on the
|
||||
basis of media cost, duplication charges, time of people involved,
|
||||
and so on. (You will not be required to justify it to the
|
||||
Copyright Holder, but only to the computing community at large
|
||||
as a market that must bear the fee.)
|
||||
|
||||
"Freely Available" means that no fee is charged for the item
|
||||
itself, though there may be fees involved in handling the item.
|
||||
It also means that recipients of the item may redistribute it
|
||||
under the same conditions they received it.
|
||||
|
||||
1. You may make and give away verbatim copies of the source form of the
|
||||
Standard Version of this Package without restriction, provided that you
|
||||
duplicate all of the original copyright notices and associated disclaimers.
|
||||
|
||||
2. You may apply bug fixes, portability fixes and other modifications
|
||||
derived from the Public Domain or from the Copyright Holder. A Package
|
||||
modified in such a way shall still be considered the Standard Version.
|
||||
|
||||
3. You may otherwise modify your copy of this Package in any way, provided
|
||||
that you insert a prominent notice in each changed file stating how and
|
||||
when you changed that file, and provided that you do at least ONE of the
|
||||
following:
|
||||
|
||||
a) place your modifications in the Public Domain or otherwise make them
|
||||
Freely Available, such as by posting said modifications to Usenet or
|
||||
an equivalent medium, or placing the modifications on a major archive
|
||||
site such as uunet.uu.net, or by allowing the Copyright Holder to include
|
||||
your modifications in the Standard Version of the Package.
|
||||
|
||||
b) use the modified Package only within your corporation or organization.
|
||||
|
||||
c) rename any non-standard executables so the names do not conflict
|
||||
with standard executables, which must also be provided, and provide
|
||||
a separate manual page for each non-standard executable that clearly
|
||||
documents how it differs from the Standard Version.
|
||||
|
||||
d) make other distribution arrangements with the Copyright Holder.
|
||||
|
||||
4. You may distribute the programs of this Package in object code or
|
||||
executable form, provided that you do at least ONE of the following:
|
||||
|
||||
a) distribute a Standard Version of the executables and library files,
|
||||
together with instructions (in the manual page or equivalent) on where
|
||||
to get the Standard Version.
|
||||
|
||||
b) accompany the distribution with the machine-readable source of
|
||||
the Package with your modifications.
|
||||
|
||||
c) give non-standard executables non-standard names, and clearly
|
||||
document the differences in manual pages (or equivalent), together
|
||||
with instructions on where to get the Standard Version.
|
||||
|
||||
d) make other distribution arrangements with the Copyright Holder.
|
||||
|
||||
5. You may charge a reasonable copying fee for any distribution of this
|
||||
Package. You may charge any fee you choose for support of this
|
||||
Package. You may not charge a fee for this Package itself. However,
|
||||
you may distribute this Package in aggregate with other (possibly
|
||||
commercial) programs as part of a larger (possibly commercial) software
|
||||
distribution provided that you do not advertise this Package as a
|
||||
product of your own. You may embed this Package's interpreter within
|
||||
an executable of yours (by linking); this shall be construed as a mere
|
||||
form of aggregation, provided that the complete Standard Version of the
|
||||
interpreter is so embedded.
|
||||
|
||||
6. The scripts and library files supplied as input to or produced as
|
||||
output from the programs of this Package do not automatically fall
|
||||
under the copyright of this Package, but belong to whoever generated
|
||||
them, and may be sold commercially, and may be aggregated with this
|
||||
Package. If such scripts or library files are aggregated with this
|
||||
Package via the so-called "undump" or "unexec" methods of producing a
|
||||
binary executable image, then distribution of such an image shall
|
||||
neither be construed as a distribution of this Package nor shall it
|
||||
fall under the restrictions of Paragraphs 3 and 4, provided that you do
|
||||
not represent such an executable image as a Standard Version of this
|
||||
Package.
|
||||
|
||||
7. C subroutines (or comparably compiled subroutines in other
|
||||
languages) supplied by you and linked into this Package in order to
|
||||
emulate subroutines and variables of the language defined by this
|
||||
Package shall not be considered part of this Package, but are the
|
||||
equivalent of input as in Paragraph 6, provided these subroutines do
|
||||
not change the language in any way that would cause it to fail the
|
||||
regression tests for the language.
|
||||
|
||||
8. Aggregation of this Package with a commercial distribution is always
|
||||
permitted provided that the use of this Package is embedded; that is,
|
||||
when no overt attempt is made to make this Package's interfaces visible
|
||||
to the end user of the commercial distribution. Such use shall not be
|
||||
construed as a distribution of this Package.
|
||||
|
||||
9. The name of the Copyright Holder may not be used to endorse or promote
|
||||
products derived from this software without specific prior written permission.
|
||||
|
||||
10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
The End
|
4
BUGS
Normal file
4
BUGS
Normal file
@ -0,0 +1,4 @@
|
||||
Please send your bug reports to me directly, at
|
||||
imacat@mail.imacat.idv.tw.
|
||||
|
||||
Sorry that mailing list is not available yet till this time.
|
22
Build.PL
Executable file
22
Build.PL
Executable file
@ -0,0 +1,22 @@
|
||||
#! /usr/bin/perl -w
|
||||
use strict;
|
||||
use Module::Build;
|
||||
|
||||
my $build = Module::Build->new(
|
||||
dist_name => "Locale-Maketext-Gettext",
|
||||
dist_version => "1.28",
|
||||
dist_abstract => "Joins gettext and Maketext frameworks",
|
||||
dist_author => "imacat <imacat\@mail.imacat.idv.tw>",
|
||||
license => "perl",
|
||||
sign => 1,
|
||||
|
||||
script_files => [ "script/maketext" ],
|
||||
requires => {
|
||||
"perl" => "5.8.0",
|
||||
},
|
||||
add_to_cleanup => [ "t/test_native.po", "t/locale/en/LC_MESSAGES/test_native.mo" ],
|
||||
);
|
||||
|
||||
$build->create_build_script;
|
||||
|
||||
__END__
|
674
COPYING
Normal file
674
COPYING
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
581
Changes
Normal file
581
Changes
Normal file
@ -0,0 +1,581 @@
|
||||
Locale-Maketext-Gettext change log
|
||||
|
||||
2009-06-27 version 1.28
|
||||
Build script fix. No code changes.
|
||||
1. Build.PL: Removed the build_requires, as they are not
|
||||
required by the build process, but by the test process.
|
||||
The build process should not be blocked by them.
|
||||
Suggested by Ryan Niebur <ryanryan52@gmail.com> and
|
||||
Adam Kennedy <adamkennedybackup@gmail.com>
|
||||
(and Audrey Tang).
|
||||
|
||||
2009-04-28 version 1.27
|
||||
Test suite fix. No code changes.
|
||||
1. t/03-errors.t: Fixed the find_system_mo() subroutine to
|
||||
exclude MO files with special characters that might be
|
||||
considered as code by Locale::Maketext.
|
||||
2. t/02-big-endian.t: Fixed the native-built MO file test
|
||||
and moved the $POfile and $MOfile file name assignment
|
||||
to the beginning, to ensure that their values are
|
||||
assigned even if GNU gettext is not installed and
|
||||
the test is skipped on the target test system.
|
||||
|
||||
2008-11-11
|
||||
1. INSTALL: Fixed the grammer, changed "none" to "None.".
|
||||
|
||||
2008-04-22 version 1.26
|
||||
Documentation fix. No code changes.
|
||||
1. bin/maketext: Moved to script/maketext.
|
||||
|
||||
2008-04-21
|
||||
1. TODO: Added.
|
||||
2. Artistic and COPYING: Added.
|
||||
3. INSTALL: Added. Installation instructions moved from README
|
||||
to INSTALL.
|
||||
|
||||
2008-04-11 version 1.25
|
||||
Test suite fix. No code changes.
|
||||
1. t/03-errors.t and t/08-f-errors.t: Added find_system_mo(), to
|
||||
select a system MO file that we can use.
|
||||
|
||||
2008-02-26 version 1.24
|
||||
Test and build suite fix. No code changes.
|
||||
1. t/02-big-endian.t: Added creating PO at run time, in order
|
||||
to work with GNU gettext < 0.15 whose msgfmt does not support
|
||||
msgctxt yet. This should work with both older and newer
|
||||
GNU gettext.
|
||||
2. t/test_native.po: Removed. It is now generated by
|
||||
t/02-big-endian.t at run time.
|
||||
3. Makefile.PL: Added "clean" to clean-up possible existing
|
||||
test_native.po and test_native.mo.
|
||||
4. Build.PL: Added "add_to_cleanup" to clean-up possible existing
|
||||
test_native.po and test_native.mo.
|
||||
5. Build.PL: Added "build_requires".
|
||||
6. t/08-f-errors.t: Fixed so that it finds the newest MO file
|
||||
found on the system, in order to avoid lagacy MO files.
|
||||
(gettext 0.10 in 1995?)
|
||||
7. t/08-f-errors.t: Fixed test 38 so that it skips in the eval()
|
||||
block, and dumps the error on failure.
|
||||
8. Changes: Added several missing change notes in version 1.23.
|
||||
|
||||
2008-02-19 version 1.23
|
||||
Added support for GNU gettext pgettext() as pmaketext(), to
|
||||
translate text messages in a particular context.
|
||||
1. Gettext.pm: Added the pmaketext() method as an equivalent of
|
||||
the pgettext() function in GNU gettext, to look up the text
|
||||
message in a particular context, according to the suggestion
|
||||
by Chris Travers.
|
||||
2. Functions.pm: Added the pmaketext() function as an equivalent
|
||||
of the pgettext() function in GNU gettext, and the dpmaketext()
|
||||
function as an equivalent of the dpgettext() function in GNU
|
||||
gettext, to look up the text message in a particular context,
|
||||
according to the suggestion by Chris Travers.
|
||||
3. Gettext.pm and Functions.pm: Fixed documentation and comments.
|
||||
Changed "perl" as "Perl". Removed contractions and replaced
|
||||
them with full sayings, in order to work with syntax
|
||||
highlighting. Removed emotional marks for the same reason.
|
||||
4. Makefile.PL: Added conditional checks for whether LICENSE is
|
||||
available in ExtUtils::MakeMaker.
|
||||
5. Gettext.pm and Functions.pm: Added xgettext keyword notation
|
||||
for dmaketext(), pmaketext() and dpmaketext().
|
||||
6. t/locale/*/LC_MESSAGES/*.mo, t/test_native.po: Added messages
|
||||
with contexts for pmaketext() testings.
|
||||
7. t/*.t: Added tests for pmaketext() and dpmaketext().
|
||||
8. Gettext.pm: Fixed the failure_handler_auto() method to remove
|
||||
the message context from the message key before sending to
|
||||
the failure lexicon. The failure_handler_auto() method
|
||||
differs from its Locale::Maketext parent from now on.
|
||||
|
||||
2007-03-28 version 1.22
|
||||
1. t/*-f-*.t: Moved Locale::Maketext::Gettext::Functions::_reset()
|
||||
from the end of each set of tests, to the front of each set of
|
||||
tests. If at the end of the test set, it would not be run if
|
||||
the eval{} block fails.
|
||||
2. Gettext.pm, Functions.pm and maketext: Updated the URL of the
|
||||
GNU gettext manual in the their POD documents.
|
||||
3. Functions.pm: The example in its POD document is updated to show
|
||||
more of the nature of Locale::Maketext.
|
||||
|
||||
2007-03-28 version 1.21
|
||||
1. 04-encodings.t and 09-f-encodings.t: Inserted test#26 to test the
|
||||
$@ error message. It is an encode() error that is not affected
|
||||
by the Locale::Maketext $@ change with "local $@".
|
||||
2. 06-racing.t: Added $LOOKUP_FAILURE as look-up failure flag. Added
|
||||
a simple subroutine to handle lookup failure. Test that to see if
|
||||
we are really die from lookup failure.
|
||||
3. Gettext.pm, Functions.pm and 09-f-encodings.t: Renamed
|
||||
ENCODING_SET to USERSET_ENCODING. USERSET_ENCODING is set to
|
||||
the encoding user specified. Future test should use "exists",
|
||||
but not "defined", as user may supply undef on this.
|
||||
4. Gettext.pm: Renaming _lmg_failure_handler_auto() to
|
||||
failure_handler_auto(). It should be OK to override it, and this
|
||||
help subclasses to employ our version.
|
||||
5. Functions.pm: Note why we don't use $@ but @ as the prototypes of
|
||||
__(), N_(), maketext().
|
||||
6. Functions.pm: Removed unused global variable $ENCODING.
|
||||
7. Functions.pm: Renamed %VARS to %PARAMS. Changed $KEY_ENCODING
|
||||
to $PARAMS{"KEY_ENCODING"}. Changed $DIE_FOR_LOOKUP_FAILURES to
|
||||
$PARAMS{"DIE_FOR_LOOKUP_FAILURES"}. Changed $ENCODE_FAILURE to
|
||||
$PARAMS{"ENCODE_FAILURE"}.
|
||||
8. Gettext.pm and Functions.pm: Changed the returning line of
|
||||
encoding(), key_encoding() and die_for_lookup_failures() to one
|
||||
conditional line. This is more neat.
|
||||
9. Functions.pm: Updated _reset(), resetting $PARAMS{"KEY_ENCODING"} to
|
||||
"US-ASCII" instead of undef, add resetting
|
||||
$PARAMS{"DIE_FOR_LOOKUP_FAILURES"} to 0;
|
||||
10. Gettext.pm: Updated failure_handler_auto(), check if this method
|
||||
is revoked statically.
|
||||
11. t/*-f-*.t: Added Locale::Maketext::Gettext::Functions::_reset() to
|
||||
the end of each set of tests, to reset the environment.
|
||||
12. Gettext.pm: Added fail_with() as a wrapper to record the user set
|
||||
lookup failure handler, so that we can safely switch with
|
||||
die_for_lookup_failures(). A new attribute {"USERSET_FAIL"} is
|
||||
added to record it. All references to fail_with() in other places
|
||||
of the code are changed to SUPER::fail_with(). fail_with() is
|
||||
only for the user since it will update the registered user
|
||||
preference.
|
||||
13. Gettext.pm and Functions.pm: In maketext(), check if the key is
|
||||
Perl utf8 text with Encode::is_utf8() first before decode() the
|
||||
key, so that user can safely run a multibyte-awared script.
|
||||
14. Gettext.pm and Functions.pm: In maketext(), check if the key is
|
||||
Perl utf8 text with Encode::is_utf8() first before encode(), for
|
||||
empty/invalid lexicon with key_encoding() set but no output
|
||||
encoding, so that we can have a real pass through. In the case
|
||||
of an empty/invalid lexicon, the user should be responsible for
|
||||
the output encoding. Added $keyd as the decoded() $key, so
|
||||
that we can check the original $key later.
|
||||
15. Functions.pm: In __(), removed unused variables $encoding,
|
||||
$lh_encoding and $key_encoding.
|
||||
16. maketext: In parse_args(), check the return value of the eval { }
|
||||
block instead of $@, and remove the extra new line when outputing
|
||||
the error in $@.
|
||||
17. maketext: Added an example at the DESCRIPTION chapter of the
|
||||
POD documentation.
|
||||
18. Gettext.pm: Added a note on the relation of fail_with()
|
||||
die_for_lookup_failures() at the description of the
|
||||
die_for_lookup_failures() method at the METHODS section
|
||||
of the POD documentation.
|
||||
19. Makefile.PL: Added LICENSE attribute as "perl".
|
||||
|
||||
2007-03-28 version 1.20
|
||||
Rewrite to follow the error handler design of Locale::Maketext, i.e.
|
||||
the fail_with() method, instead of our own.
|
||||
Clean up encoding mess. You may need to check if your application
|
||||
was depending on the previous wrong, hard-to-handle behavior on look
|
||||
up failurs. The new behavior should be easier to deal with.
|
||||
1. Gettext.pm: In the textdomain() function, make sure {"ENCODING"}
|
||||
is not set to undef when MO file does not exists.
|
||||
2. Functions.pm: In the encoding() function, removed a piece of long
|
||||
gone, commented code.
|
||||
3. Gettext.pm and Functions.pm: In the encoding(), textdomain() and
|
||||
the _get_handle() function, add a flag {"ENCODING_SET"} to tag if
|
||||
we should respect the encoding() setting of the user. If there is
|
||||
no user preferred encoding(), when obtaining language handle with
|
||||
_get_handle() or textdomain(), encoding() will change to the
|
||||
output encoding() to that of the corresponding MO file.
|
||||
4. 09-f-encoding.t: Added "delete $VARS{"ENCODING_SET"}" in the end
|
||||
of each test to clean up the environment.
|
||||
5. Gettext.pm: Update the version number to 1.20.
|
||||
6. Functions.pm: Update the version number to 0.10.
|
||||
7. t/99-pod.t: Added.
|
||||
8. Makefile.PL: Stylish clean-up and update. Added "SIGN".
|
||||
9. Build.PL: Added.
|
||||
|
||||
2007-03-27
|
||||
1. Gettext.pm: Added _lmg_failure_handler_auto(), as a replacement
|
||||
of Locale::Maketext's failure_handler_auto(). Locale::Maketext's
|
||||
failure_handler_auto() until version 1.10 has problem with
|
||||
message keys without any brackets. See bug#33938 on rt.cpan.org.
|
||||
It's content was simply copied from failure_handler_auto().
|
||||
2. Gettext.pm: Removed classes Locale::Maketext::Gettext::_AUTO,
|
||||
Locale::Maketext::Gettext::_AUTO::i_default,
|
||||
Locale::Maketext::Gettext::_EMPTY and
|
||||
Locale::Maketext::Gettext::_EMPTY::i_default. We are using
|
||||
Locale::Maketext's fail_with() method to deal with look up errors
|
||||
rather than making dummy language handles and deal with them by
|
||||
ourselves. This simplify things, making the code more compatible
|
||||
with Locale::Maketext. As a result, Locale::Maketext's
|
||||
fail_with() method and {"fail"} attribute are working now.
|
||||
3. Gettext.pm: In the maketext() method, removed the code that deal
|
||||
with look up errors by ourselves. Now we handle this with the
|
||||
{"fail"} attribute and the _lmg_failure_handler_auto() method,
|
||||
following the original Locale::Maketext's design.
|
||||
4. Gettext.pm: In the textdomain() method, added clear_isa_scan() in
|
||||
the end to clear the ISA handler look up cache table. This way we
|
||||
are not affected by the cache of _lmg_failure_handler_auto()
|
||||
when switching domain with textdomain().
|
||||
5. Gettext.pm and Functions.pm: In encoding() and key_encoding(),
|
||||
feeding undef delete the property. This is to unify the practice
|
||||
of "exists" and "defined" tests. All tests should use "exists"
|
||||
instead of "defined" now.
|
||||
6. Functions.pm: Added classes
|
||||
Locale::Maketext::Gettext::Functions::_EMPTY and
|
||||
Locale::Maketext::Gettext::Functions::_EMPTY::i_default as a
|
||||
dummy locale.
|
||||
7. Functions.pm: Add _get_empty_handle() to return the dummy locale,
|
||||
with die_for_lookup_failures() properly set. This replaces the
|
||||
$_EMPTY setting in the beginning of the file.
|
||||
8. Functions.pm: In the _get_handle() method added unset the
|
||||
key_encoding() before returning the language handle.
|
||||
key_encoding() is handled by Locale::Maketext::Gettext::Functions.
|
||||
Locale::Maketext::Gettext does not need to handle key_encoding().
|
||||
This is to follow the nature of functional API that
|
||||
key_encoding() should apply to all the following session in
|
||||
functional API.
|
||||
9. Gettext.pm and Functions.pm: In maketext(), stop playing magic
|
||||
with encoding() and key_encoding() that automatically encode()
|
||||
text back to key_encoding() when lookup fails. The result is
|
||||
too unpredictable. The application should specify which encoding
|
||||
they want themselves.
|
||||
|
||||
2007-03-22 version 1.18
|
||||
Fixes for Perl 5.9. Locale::Maketext in Perl 5.9 does not set $@
|
||||
as its error message. Tests replying on $@ may fail for this. But
|
||||
I should check the return value of the eval{} block rather than $@
|
||||
anyway.
|
||||
1. t/*.t: Adition of $r as the return value of the eval{} blocks.
|
||||
Addition of "return 1;" to the eval{} blocks to specify the return
|
||||
values. Changing tests "ok($@, "");" to "ok($r, 1);". Changing
|
||||
tests "ok($@, qr/maketext doesn't know how to say/);" and
|
||||
"ok($@, qr/does not map to/);" to "ok($r, undef)". This is to
|
||||
be refined. It is necessary to test if it fails by our expected
|
||||
reason rather than only knowing that it fails.
|
||||
2. Update the version number of Locale::Maketext::Gettext to match
|
||||
the distribution version.
|
||||
|
||||
2005-04-27 version 1.17
|
||||
1. Changes: Typo fixed.
|
||||
|
||||
2005-04-26 version 1.16
|
||||
Test suite fixes.
|
||||
1. 02-big-endian.t: In test 7, 8, $MOfile and $POfile are quoted
|
||||
when sending to the shell (backticks), to be safe to spaces and
|
||||
other special shell characters in their paths.
|
||||
2. 11-command-line.t: In all tests $maketext is quoted when sending
|
||||
to the shell (backticks), to be safe to spaces and other special
|
||||
shell characters in its path. This should solve the CPAN tester
|
||||
failures 200029, 200332 and 200331. Thanks to Max Maischein
|
||||
<corion@corion.net> for testing and reporting this.
|
||||
3. Changes: File edited to widen line limit from 60 columns to 79
|
||||
columns, to ease the reading.
|
||||
4. THANKS: Updated.
|
||||
|
||||
2005-04-26 version 1.15
|
||||
1. SIGNATURE: Included Modules::Signature gpg signature file added.
|
||||
2. 00-signature.t: Added.
|
||||
|
||||
2005-04-21 version 1.14
|
||||
1. maketext: Prototypes of the following subroutines are
|
||||
declared first now: main() and parse_args().
|
||||
|
||||
2005-04-20 version 1.13
|
||||
1. Changes: Addition of new unencoded UTF-8 tests is appended to the
|
||||
change log.
|
||||
2. Changes: Addition of warning of key_encoding() is appended to the
|
||||
change log.
|
||||
3. Changes: Typo fixed: "Vesion" should be "Version".
|
||||
4. Changes: Typo fixed: 2005-04-10 should be 2005-04-20.
|
||||
|
||||
2005-04-20 version 1.12
|
||||
Documentation fixes.
|
||||
1. Update the copyright year on the updated files.
|
||||
2. Changes: Version number added.
|
||||
|
||||
2005-04-19 version 1.11
|
||||
1. Gettext.pm: Using undef as encoding or key_encoding. Methods
|
||||
encoding() and key_encoding() now check the number of arguments
|
||||
instead of the argument value. When undef, the unencoded UTF-8
|
||||
text is returned.
|
||||
2. Gettext.pm: Prototype of subroutine read_mo() is declared first
|
||||
now.
|
||||
3. Gettext.pm: Deprecated subroutine readmo() is removed.
|
||||
4. Functions.pm: Prototypes of the following subroutines are declared
|
||||
first now: bindtextdomain(), textdomain(), get_handle(),
|
||||
maketext(), __(), N_(), dmaketext(), reload_text(), encoding(),
|
||||
key_encoding(), encode_failure(), die_for_lookup_failures(),
|
||||
_declare_class(), _catclass(), _init_textdomain(), _get_langs(),
|
||||
_get_handle(), _reset(), _new_rid(), _k() and _lang().
|
||||
5. 07-f-basic.t: Locale environment variables are cleared before
|
||||
running tests, to avoid confusion from the user's current locale.
|
||||
6. 10-f-switching.t: Locale environment variables are cleared before
|
||||
running tests, to avoid confusion from the user's current locale.
|
||||
7. Gettext.pm: Default KEY_ENCODING to US-ASCII. It is always
|
||||
decoded to UTF-8 first when looked up in the _AUTO lexicon, to
|
||||
ensure that the resulted text is always in UTF-8.
|
||||
8. Gettext.pm: Avoid caching undefined MO file encoding when MO file
|
||||
is not available.
|
||||
9. Gettext.pm: New attribute "MO_ENCODING" is added to to record the
|
||||
encoding of the MO file.
|
||||
10. Functions.pm: Default KEY_ENCODING to US-ASCII. It is always
|
||||
decoded to UTF-8 first when looked up in the _AUTO lexicon, to
|
||||
ensure that the resulted text is always in UTF-8.
|
||||
11. 04-encodings.t: Tests 28-33 added to test returning unencoded
|
||||
UTF-8 text.
|
||||
12. 09-f-encodings.t: Tests 28-33 added to test returning unencoded
|
||||
UTF-8 text.
|
||||
13. Gettext.pm: Warning is added to the use of key_encoding().
|
||||
14. Functions.pm: Warning is added to the use of key_encoding().
|
||||
|
||||
2005-04-05
|
||||
1. Gettext.pm: Subroutine attribute "method" is taged on the
|
||||
following methods: encoding(), key_encoding(), new(),
|
||||
subclass_init(), bindtextdomain(), textdomain(), maketext(),
|
||||
reload_text(), die_for_lookup_failures() and encode_failure().
|
||||
|
||||
2003-05-12
|
||||
1. Gettext.pm: key_encoding applied to "not found" keys only, so that
|
||||
it can be looked up in their original encoding in the %Lexicon.
|
||||
|
||||
2003-05-09 version 1.10
|
||||
1. Functions.pm: _get_handle: Fallback language handler changed from
|
||||
the failed language handler $FLH to the empty lexicon $_EMPTY.
|
||||
This has no real effect, since lookup failures are always handled
|
||||
by $FLH, but not the current language handler $LH. But this
|
||||
matches the reality.
|
||||
|
||||
2003-05-08
|
||||
1. Changes: typo (version 1.07 should be version 1.09)
|
||||
|
||||
2003-05-07
|
||||
1. Changes: An excess blank line is removed.
|
||||
|
||||
2003-05-07 version 1.09
|
||||
Test suite fix.
|
||||
1. 02-big-endian.t: Fix on $MSGFMT so that it works on more
|
||||
platforms.
|
||||
|
||||
2003-05-07 version 1.08
|
||||
Fixes mistakes from version 1.07
|
||||
1. Return the interpreter line to the maketext script. It was a
|
||||
misunderstanding at 1.07
|
||||
2. Content-Transfer-Encoding is fixed from 8bit to 7bit in the
|
||||
English MO files.
|
||||
3. t/test_native.po: Added.
|
||||
4. 02-big-endian.t: Test suite for native-built MO files are added.
|
||||
Please report your failures.
|
||||
|
||||
2003-05-05 version 1.07
|
||||
Bug fixes.
|
||||
1. Fix to the interpreter line in the maketext script so that it can
|
||||
be replaced with correct interpreter at make time.
|
||||
2. 11-command-line.t: script location changed from lib/maketext to
|
||||
blib/script/maketext.
|
||||
3. C locale is added to the test suite.
|
||||
4. 11-command-line.t: Locales en, zh_TW, zh_CN are remove from the
|
||||
test suite, to avoid perl warnings from systems that did not
|
||||
install these locales.
|
||||
5. 11-command-line.t: $ENV{"LANGUAGE"} controls added.
|
||||
|
||||
2003-05-04 version 1.06
|
||||
1. Language function override is not available for L::M::G::F and the
|
||||
maketext script. I almost forgot this problem. Notice is added
|
||||
to the documentation. Suggestions are welcome.
|
||||
|
||||
2003-05-03 version 1.06
|
||||
Introducing "maketext", a command line interface to
|
||||
Locale::Maketext::Gettext (and Locale::Maketext).
|
||||
1. The maketext script is added, a command line interface to
|
||||
Locale::Maketext::Gettext (and Locale::Maketext).
|
||||
|
||||
2003-05-03 version 1.05
|
||||
Test suites fixes. This fixes the failures reported from CPAN
|
||||
testers. Failures reported from CPAN testers are caused by
|
||||
Archive-Tar called by CPANPLUS, but not by Locale::Maketext::Gettext
|
||||
itself. Bug report concerning this problem is already submitted to
|
||||
Archive-Tar.
|
||||
1. Test suite temporarily files test_dyn.mo are removed from
|
||||
MANIFEST.
|
||||
2. File::Copy is used instead of link in the test suites to enable
|
||||
tests on platforms that does not support hard links (Win32, for
|
||||
example).
|
||||
3. Temporarily files are cleaned up at the end of 05-switching.t and
|
||||
10-f-switching.t.
|
||||
Upgrade is not required if you are using version 1.04.
|
||||
|
||||
2003-05-02 version 1.04
|
||||
1. Support for MO files without encoding specified was added. I
|
||||
don't know there are MO files born without its encoding. ^^;
|
||||
2. L::M::G::F: textdomain() now works for default system locale
|
||||
directories, too. For domains that are not binded with
|
||||
bindtextdomain(), it searches the system locale directories to
|
||||
find the domain MO files. Unlike textdomain() in L::M::G, it
|
||||
remembers the search result in order to build the index key.
|
||||
3. Tests for default system locale directory search are added. It
|
||||
may be skipped, though.
|
||||
|
||||
2003-05-02 version 1.03
|
||||
1. L::M::G: A algorism bug about key_encoding with auto-lexicon was
|
||||
fixed.
|
||||
2. L::M::G::F: I decide to give up mod_perl safety for encoding,
|
||||
key_encoding, encode_failure and die_for_lookup_failures().
|
||||
POSIX::setlocale() didn't solve this problem, either. Use L::M::G
|
||||
if you need that. Suggestions and solutions are welcome.
|
||||
3. L::M::G: FLH (Failure language handler) is added to
|
||||
help switching the die_for_lookup_failures() setting.
|
||||
Maketext can be slightly faster.
|
||||
|
||||
2003-05-01
|
||||
Labor's Day!
|
||||
A Major rewrite to Locale::Maketext::Gettext::Functions.
|
||||
1. Packages are declared by a random class ID, instead of by its text
|
||||
domain previously, in order for a text domain to be redeclared
|
||||
with different sets of languages infinitely. This solves the
|
||||
problem where languages cannot to be removed at run-time. You can
|
||||
add/remove languages/MO files at run time now. You can also
|
||||
bindtextdomain() to another directory after setting textdomain().
|
||||
This is not possible to the object interface of
|
||||
Locale::Maketext::Gettext (and Locale::Maketext).
|
||||
2. fork_and_test is removed from the test suite. It does not seem to
|
||||
be required by the current random class ID system anymore.
|
||||
3. The used of ($t1..$t6) is replaced by ($_[0]..$_[5]) in to
|
||||
05-switching.t.
|
||||
4. Garbage collection is added. Language handles associated with
|
||||
abandoned localization classes are dropped in time, in order to
|
||||
reduce memory used.
|
||||
|
||||
2003-04-30
|
||||
1. L::M::G::F: I forgot to document dmaketext, too. ^^;
|
||||
But, no, I will not put a third release today!
|
||||
2. L::M::G::F: Fixes to documentation typos.
|
||||
3. maketext() and __() are exchanged. maketext() is a wrapper to
|
||||
__() now. The speed of __() should be slightly faster.
|
||||
|
||||
2003-04-30 version 1.02
|
||||
Documentation fixes.
|
||||
1. L::M::G::F: Documentation fixes. get_handle was not included in
|
||||
the documentation. ^^; I forgot to put it in.
|
||||
2. README was updated. L::M::G::F is included in the README. Also,
|
||||
the installation procedure is updated, too. I forgot to update it
|
||||
last time.
|
||||
|
||||
2003-04-30 version 1.01
|
||||
Improvements to Locale::Maketext::Gettext::Functions.
|
||||
1. L::M::G::F: Documentation fixes. Lots of errors sit there in the
|
||||
previous documentation. It's impossible to work if you follow the
|
||||
previous documentation. ^^; Ha ha...
|
||||
2. L::M::G: Map the language i-default to the locale C.
|
||||
3. L::M::G::F: Map the locale C to the language i-default.
|
||||
4. fork_and_test is added to the test suite to test without polluting
|
||||
the package space. It is slow, though. ^^;
|
||||
5. L::M::G::F: Several test suites are added.
|
||||
6. L::M::G::F: Error tolerance is largely improved.
|
||||
7. L::M::G: New method subclass_init() is added. Object
|
||||
initialization is moved from the new method to the subclass_init()
|
||||
method, so that another subclass may inherit it further.
|
||||
8. L::M::G::F: The "experimental" warning is removed. Large amount of
|
||||
errors can be handled gracefully now.
|
||||
|
||||
2003-04-28
|
||||
1. TestPkg/L10N.pm is renamed as T_L10N.pm. It is neater. A
|
||||
TestPkg/ subdirectory is not necessary.
|
||||
2. Change log is fixed. I forgot to put the version number 0.07.
|
||||
3. Also, the version number should become 1.00, for the joining of
|
||||
Locale::Maketext::Gettext::Functions. ^_*'
|
||||
|
||||
2003-04-28 version 0.07 (1.00)
|
||||
Introducing Locale::Maketext::Gettext::Functions, a functional
|
||||
interface to Locale::Maketext::Gettext.
|
||||
1. The first Locale::Maketext::Gettext::Functions is out. It works!
|
||||
^_*' But it is still experimental. It cannot deal with real
|
||||
world problems still. ^^;
|
||||
2. Documentation was fixed so that it is neater.
|
||||
|
||||
2003-04-27
|
||||
1. The name of the _AUTO lexicon package is shorten to
|
||||
Locale::Maketext::Gettext::_AUTO.
|
||||
2. Documentation rearrange.
|
||||
|
||||
2003-04-27 version 0.06
|
||||
Improvements.
|
||||
1. textdomain() works for default system locale directories now. For
|
||||
domains that are not binded with bindtextdomain(), it searches the
|
||||
system locale directories to find the MO file. No test suite is
|
||||
available for this functionality. I cannot predict what MO files
|
||||
are available in your system locale directories. ^^; Please
|
||||
report bugs if it does not work.
|
||||
2. Slave package Locale::Maketext::Gettext::_AUTO::L10N is added, in
|
||||
order to process the _AUTO Lexicon seperately. This saves
|
||||
resources when user change the die_for_lookup_failures() setting.
|
||||
Changing die_for_lookup_failures() setting won't trigger copying
|
||||
and replacing your whole %Lexicon anymore. As an effect, the
|
||||
cached compiled result of the _AUTO lexicon is preserved and the
|
||||
compilation overhead from Locale::Maketext is greatly reduced.
|
||||
3. read_mo() is added to retire the readmo(). Use of readmo() is
|
||||
deprecated. This idea is inspired by the implementation of
|
||||
readmo() as "parse_mo" in Locale::Maketext::Lexicon by Autrijus.
|
||||
There is far too much meta infomation to be returned other than
|
||||
its encoding. It's not possible to change the API for each new
|
||||
requirement. To enable sharing of the algorithm used in read_mo()
|
||||
with whoever need it, it's necessary to limit its function to read
|
||||
and return the raw data, leaving all the other jobs to its caller.
|
||||
4. For the same reason, caching control is removed from read_mo(),
|
||||
too. read_mo() read the MO file and return the %Lexicon only. It
|
||||
really reads. Nothing more. ^_*'
|
||||
|
||||
2003-04-27 version 0.05
|
||||
Bug and documentation fixes.
|
||||
1. New method key_encoding was added. The _AUTO lexicon is itself
|
||||
not multibyte-safe. You can specify the encoding of your keys if
|
||||
you are using non-ASCII keys. This is not a solution, but a
|
||||
workaround.
|
||||
2. New method encode_failure was added. The default action when
|
||||
encode fails changed from FB_CROAK to FB_DEFAULT. I have changed
|
||||
my mind. GNU gettext never fails.
|
||||
3. The paragraph about Locale::Maketext::Lexicon at the NOTES section
|
||||
in the documentation is updated. The paragraph about msgunfmt is
|
||||
removed.
|
||||
4. The README file was updated.
|
||||
5. The strange line "exists ${"$class\::Lexicon"}{$key};" is removed.
|
||||
That problem seems to be solved. It is not required anymore.
|
||||
|
||||
2003-04-25 version 0.04
|
||||
Documentation fixes. Upgrade is not required if you are using version
|
||||
0.03.
|
||||
|
||||
2003-04-25 version 0.03
|
||||
Bug fixes.
|
||||
1. Fixed clashing of the die_for_lookup_failures() setting from
|
||||
multiple instances.
|
||||
2. Change log is rewritten, to my own format.
|
||||
3. A new racing test suite is added. The old racing test suite was
|
||||
renamed as t-switching.
|
||||
4. Redundant initialization of $LH->{"LOCALEDIRS"} in
|
||||
bindtextdomain() is removed.
|
||||
5. An old line at die_for_lookup_failures() which initialize a wrong
|
||||
$LH->{"LOCALE"} is removed.
|
||||
6. Removed 2 incorrect notice in the documentation. There will not
|
||||
be infinite loops for bindtextdomain() and textdomain(), whatever
|
||||
value it takes. Apparently I had made a mistake. ^^;
|
||||
7. Several typos in the comments are fixed.
|
||||
8. Sanity checks to the MO file is moved into readmo(). Cache now
|
||||
has a higher precedence than the sanity checks, which conforms
|
||||
with the global design.
|
||||
9. More documentation was added to the SYNOPSIS.
|
||||
10. Sanity checks for whether a method is invoked as a static method
|
||||
are added. Maketext use static variables. We should not clash
|
||||
them.
|
||||
11. As a result of the above, the maketext method is no more static.
|
||||
It is an instance method, meaning that MyPkg::L10N::en->maketext
|
||||
does not work anymore.
|
||||
12. Instance lexicon is initialized in the new method. I almost
|
||||
forgot it. Thanks to the test suite. :p
|
||||
|
||||
2003-04-25 version 0.02
|
||||
Class/object design fixes.
|
||||
1. I did tell the difference from class variables to instance
|
||||
variables. Forgive me, I had no experience with object-oriented
|
||||
programming at all, not even OO for perl. :p Just a few Java
|
||||
books. Anyway, the problem with clashing class variables is
|
||||
fixed. Most class variables are moved into instance variables.
|
||||
2. Solved the default output encoding problem by using the encoding
|
||||
of the MO file as the default encoding.
|
||||
3. reload_text method is added to purge the MO file cache, so that
|
||||
applications do not need to be restarted when their MO file
|
||||
updates.
|
||||
4. MO files of different byte orders are supported now. Big-endian
|
||||
MO files support is added.
|
||||
5. die_for_lookup_failures() method was added. The default behavior
|
||||
changed to "never fails", as GNU gettext does.
|
||||
6. A test suite is added.
|
||||
|
||||
2003-04-24 version 0.01
|
146
INSTALL
Normal file
146
INSTALL
Normal file
@ -0,0 +1,146 @@
|
||||
Locale-Maketext-Gettext Installation Guide
|
||||
|
||||
* Table of Contents
|
||||
|
||||
* System Requirements
|
||||
* Installation Instruction
|
||||
** Install with ExtUtils::MakeMaker
|
||||
** Install with Module::Build
|
||||
** Install with the CPAN Shell
|
||||
** Install with the CPANPLUS Shell
|
||||
|
||||
|
||||
* System Requirements
|
||||
|
||||
1. Perl, version 5.8.0 or above. Locale::Maketext::Gettext uses
|
||||
the utf8 text internally that is only available since 5.8.0. You can
|
||||
run perl -v to see your current Perl version. If you don't have
|
||||
Perl, or if you have an older version of Perl, you can download and
|
||||
install/upgrade it from Perl website.
|
||||
|
||||
http://www.perl.com/
|
||||
|
||||
If you are using MS-Windows, you can download and install
|
||||
ActiveState ActivePerl.
|
||||
|
||||
http://www.activestate.com/
|
||||
|
||||
2. Required Perl modules: None.
|
||||
|
||||
3. Optional Perl modules: None.
|
||||
|
||||
|
||||
* Installation Instruction
|
||||
|
||||
** Install with ExtUtils::MakeMaker
|
||||
|
||||
arclog uses standard Perl installation with ExtUtils::MakeMaker.
|
||||
Follow these steps:
|
||||
|
||||
% perl Makefile.PL
|
||||
% make
|
||||
% make test
|
||||
% make install
|
||||
|
||||
When running make install, make sure you have the priviledge to
|
||||
write to the installation location. This usually requires the root
|
||||
priviledge.
|
||||
|
||||
If you are using ActivePerl under MS-Windows, you should use
|
||||
nmake instead of make. nmake can be obtained from the Microsoft FTP
|
||||
site.
|
||||
|
||||
ftp://ftp.microsoft.com/Softlib/MSLFILES/nmake15.exe
|
||||
|
||||
If you want to install into another location, you can set the
|
||||
PREFIX. For example, to install into your home when you are not
|
||||
root:
|
||||
|
||||
% perl Makefile.PL PREFIX=/home/jessica
|
||||
|
||||
Refer to the docuemntation of ExtUtils::MakeMaker for more
|
||||
installation options (by running perldoc ExtUtils::MakeMaker).
|
||||
|
||||
|
||||
** Install with Module::Build
|
||||
|
||||
You can install with Module::Build instead, if you prefer.
|
||||
Follow these steps:
|
||||
|
||||
% perl Build.PL
|
||||
% ./Build
|
||||
% ./Build test
|
||||
% ./Build install
|
||||
|
||||
When running ./Build install, make sure you have the priviledge to
|
||||
write to the installation location. This usually requires the root
|
||||
priviledge.
|
||||
|
||||
If you want to install into another location, you can set the
|
||||
--prefix. For example, to install into your home when you are not
|
||||
root:
|
||||
|
||||
% perl Build.PL --prefix=/home/jessica
|
||||
|
||||
Refer to the docuemntation of Module::Build for more
|
||||
installation options (by running perldoc Module::Build).
|
||||
|
||||
|
||||
** Install with the CPAN Shell
|
||||
|
||||
You can install with the CPAN shell, if you prefer. CPAN shell
|
||||
takes care of ExtUtils::MakeMaker and Module::Build for you:
|
||||
|
||||
% cpan Locale::Maketext::Gettext
|
||||
|
||||
Make sure you have the priviledge to write to the installation
|
||||
location. This usually requires the root priviledge. Since CPAN
|
||||
shell 1.81 you can set "make_install_make_command" and
|
||||
"mbuild_install_build_command" in your CPAN configuration to switch
|
||||
to root just before install:
|
||||
|
||||
% cpan
|
||||
cpan> o conf make_install_make_command "sudo make"
|
||||
cpan> o conf mbuild_install_build_command "sudo ./Build"
|
||||
cpan> install Locale::Maketext::Gettext
|
||||
|
||||
If you want to install into another location, you can set the
|
||||
"makepl_arg" and "mbuild_arg" in your CPAN configuration. For
|
||||
example, to install into your home when you are not root:
|
||||
|
||||
% cpan
|
||||
cpan> o conf makepl_arg "PREFIX=/home/jessica"
|
||||
cpan> o conf mbuild_arg "--prefix=/home/jessica"
|
||||
cpan> install Locale::Maketext::Gettext
|
||||
|
||||
Refer to the docuemntation of cpan for more CPAN shell commands
|
||||
(by running perldoc cpan).
|
||||
|
||||
|
||||
** Install with the CPANPLUS Shell
|
||||
|
||||
You can install with the CPANPLUS shell, if you prefer. CPANPLUS
|
||||
shell takes care of ExtUtils::MakeMaker and Module::Build for you:
|
||||
|
||||
% cpanp -i Locale::Maketext::Gettext
|
||||
|
||||
Make sure you have the priviledge to write to the installation
|
||||
location. This usually requires the root priviledge.
|
||||
|
||||
If you want to install into another location, you can set the
|
||||
"makemakerflags" and "buildflags" in your CPANPLUS configuration.
|
||||
For example, to install into your home when you are not root:
|
||||
|
||||
% cpanp
|
||||
CPAN Terminal> s conf makemakerflags "PREFIX=/home/jessica"
|
||||
CPAN Terminal> s conf buildflags "--prefix=/home/jessica"
|
||||
CPAN Terminal> install Locale::Maketext::Gettext
|
||||
|
||||
Refer to the docuemntation of cpanp for more CPANPLUS shell
|
||||
commands (by running perldoc cpanp).
|
||||
|
||||
|
||||
imacat
|
||||
2008-11-11
|
||||
imacat@mail.imacat.idv.tw
|
||||
http://www.imacat.idv.tw/
|
43
MANIFEST
Normal file
43
MANIFEST
Normal file
@ -0,0 +1,43 @@
|
||||
Artistic
|
||||
BUGS
|
||||
Build.PL
|
||||
Changes
|
||||
COPYING
|
||||
INSTALL
|
||||
lib/Locale/Maketext/Gettext.pm
|
||||
lib/Locale/Maketext/Gettext/Functions.pm
|
||||
Makefile.PL
|
||||
MANIFEST This list of files
|
||||
META.yml
|
||||
README
|
||||
script/maketext
|
||||
SIGNATURE
|
||||
t/00-signature.t
|
||||
t/01-basic.t
|
||||
t/02-big-endian.t
|
||||
t/03-errors.t
|
||||
t/04-encodings.t
|
||||
t/05-switching.t
|
||||
t/06-racing.t
|
||||
t/07-f-basic.t
|
||||
t/08-f-errors.t
|
||||
t/09-f-encodings.t
|
||||
t/10-f-switching.t
|
||||
t/11-command-line.t
|
||||
t/99-pod.t
|
||||
t/locale/C/LC_MESSAGES/test.mo
|
||||
t/locale/en/LC_MESSAGES/bad.mo
|
||||
t/locale/en/LC_MESSAGES/test.mo
|
||||
t/locale/en/LC_MESSAGES/test2.mo
|
||||
t/locale/en/LC_MESSAGES/test_be.mo
|
||||
t/locale/en/LC_MESSAGES/test_utf8.mo
|
||||
t/locale/zh_CN/LC_MESSAGES/test.mo
|
||||
t/locale/zh_CN/LC_MESSAGES/test_be.mo
|
||||
t/locale/zh_CN/LC_MESSAGES/test_utf8.mo
|
||||
t/locale/zh_TW/LC_MESSAGES/test.mo
|
||||
t/locale/zh_TW/LC_MESSAGES/test2.mo
|
||||
t/locale/zh_TW/LC_MESSAGES/test_be.mo
|
||||
t/locale/zh_TW/LC_MESSAGES/test_utf8.mo
|
||||
t/T_L10N.pm
|
||||
THANKS
|
||||
TODO
|
21
META.yml
Normal file
21
META.yml
Normal file
@ -0,0 +1,21 @@
|
||||
--- #YAML:1.0
|
||||
name: Locale-Maketext-Gettext
|
||||
version: 1.28
|
||||
abstract: Joins gettext and Maketext frameworks
|
||||
author:
|
||||
- imacat <imacat@mail.imacat.idv.tw>
|
||||
license: perl
|
||||
distribution_type: module
|
||||
configure_requires:
|
||||
ExtUtils::MakeMaker: 0
|
||||
build_requires:
|
||||
ExtUtils::MakeMaker: 0
|
||||
requires: {}
|
||||
no_index:
|
||||
directory:
|
||||
- t
|
||||
- inc
|
||||
generated_by: ExtUtils::MakeMaker version 6.52
|
||||
meta-spec:
|
||||
url: http://module-build.sourceforge.net/META-spec-v1.4.html
|
||||
version: 1.4
|
32
Makefile.PL
Executable file
32
Makefile.PL
Executable file
@ -0,0 +1,32 @@
|
||||
#! /usr/bin/perl -w
|
||||
require 5.008;
|
||||
use strict;
|
||||
use ExtUtils::MakeMaker;
|
||||
|
||||
# LICENSE is only availabe since ExtUtils::MakeMaker 6.30_01
|
||||
use vars qw(%license $eummver);
|
||||
%license = qw();
|
||||
$eummver = $ExtUtils::MakeMaker::VERSION;
|
||||
$eummver =~ s/_//;
|
||||
%license = (LICENSE => "perl") if $eummver > 6.30;
|
||||
|
||||
WriteMakefile(
|
||||
NAME => "Locale-Maketext-Gettext",
|
||||
VERSION => "1.28",
|
||||
ABSTRACT => "Joins gettext and Maketext frameworks",
|
||||
AUTHOR => "imacat <imacat\@mail.imacat.idv.tw>",
|
||||
%license,
|
||||
PREREQ_PM => { },
|
||||
SIGN => 1,
|
||||
|
||||
EXE_FILES => [ "script/maketext" ],
|
||||
dist => {
|
||||
COMPRESS => "gzip -9",
|
||||
SUFFIX => ".gz",
|
||||
},
|
||||
clean => {
|
||||
FILES => "t/test_native.po t/locale/en/LC_MESSAGES/test_native.mo",
|
||||
},
|
||||
);
|
||||
|
||||
__END__
|
54
README
Normal file
54
README
Normal file
@ -0,0 +1,54 @@
|
||||
Locale::Maketext::Gettext - Joins the gettext and Maketext frameworks
|
||||
|
||||
Locale::Maketext::Gettext joins the GNU gettext and Maketext
|
||||
frameworks. It is a subclass of Locale::Maketext that follows the
|
||||
way GNU gettext works. It works seamlessly, both in the sense of
|
||||
GNU gettext and Maketext. As a result, you enjoy both their
|
||||
advantages, and get rid of both their problems, too.
|
||||
|
||||
You start as an usual GNU gettext localization project: Work on
|
||||
PO files with the help of translators, reviewers and Emacs. Turn
|
||||
them into MO files with msgfmt. Copy them into the appropriate
|
||||
locale directory, such as
|
||||
/usr/share/locale/de/LC_MESSAGES/myapp.mo.
|
||||
|
||||
Then, build your Maketext localization class, with your base class
|
||||
changed from Locale::Maketext to Locale::Maketext::Gettext. That's
|
||||
all. ^_*'
|
||||
|
||||
|
||||
* Locale::Maketext::Gettext::Functions
|
||||
|
||||
Locale::Maketext::Gettext::Functions is a functional
|
||||
interface to Locale::Maketext::Gettext (and Locale::Maketext).
|
||||
It works completely the GNU gettext way. It plays magic to
|
||||
Locale::Maketext. No more localization class/subclasses and language
|
||||
handles are required.
|
||||
|
||||
|
||||
* The maketext script
|
||||
|
||||
The maketext script is a command-line interface to
|
||||
Locale::Maketext::Gettext (and Locale::Maketext). It can be used in
|
||||
shell scripts, etc, to translate, maketext and return the
|
||||
result. It enables Maketext to be integrated into other programming
|
||||
languages/systems, like bash/csh, python, PHP, C, etc. It works
|
||||
like the command-line program gettext.
|
||||
|
||||
|
||||
* Installation
|
||||
|
||||
Read INSTALL for instructions on how to install
|
||||
Locale::Maketext::Gettext.
|
||||
|
||||
|
||||
* News, Changes and Updates
|
||||
|
||||
Refer to the Changes for changes, bug fixes, updates, new functions, etc.
|
||||
|
||||
|
||||
* Copyright
|
||||
|
||||
Copyright (c) 2003-2007 imacat. All rights reserved. This program is free
|
||||
software; you can redistribute it and/or modify it under the same terms
|
||||
as Perl itself.
|
65
SIGNATURE
Normal file
65
SIGNATURE
Normal file
@ -0,0 +1,65 @@
|
||||
This file contains message digests of all files listed in MANIFEST,
|
||||
signed via the Module::Signature module, version 0.55.
|
||||
|
||||
To verify the content in this distribution, first make sure you have
|
||||
Module::Signature installed, then type:
|
||||
|
||||
% cpansign -v
|
||||
|
||||
It will check each file's integrity, as well as the signature's
|
||||
validity. If "==> Signature verified OK! <==" is not displayed,
|
||||
the distribution may already have been compromised, and you should
|
||||
not run its Makefile.PL or Build.PL.
|
||||
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
SHA1 be0627fff2e8aef3d2a14d5d7486babc8a4873ba Artistic
|
||||
SHA1 f044bfe71c57b6f25c659bc0a6067aa854bc8343 BUGS
|
||||
SHA1 7d6278e57e33472b167335a5435081f307f0dc70 Build.PL
|
||||
SHA1 8624bcdae55baeef00cd11d5dfcfa60f68710a02 COPYING
|
||||
SHA1 5863e86e8a20bbb63b3fd295520b861fa87db0c7 Changes
|
||||
SHA1 e9345adfeb32db567cd1be52f3f27307943a36bc INSTALL
|
||||
SHA1 c7d9c9b334b816e6f06473647cd9a054152a44c9 MANIFEST
|
||||
SHA1 39589ded15e1d09a79c41391392d249de3708f4a META.yml
|
||||
SHA1 ec92e11b76afaa05f67d83a6e32056505a45c99e Makefile.PL
|
||||
SHA1 b699f73f5fa33123b2f4f1b210665e295900c74d README
|
||||
SHA1 3db402b52e04cf5a6e60291c23aac8c16f2db810 THANKS
|
||||
SHA1 85dd5ac895cc0a5b95827060999578d8ce8d41dd TODO
|
||||
SHA1 f9deac7b12cc6a3cb18b7f5282f9e6a1e1a624b9 lib/Locale/Maketext/Gettext.pm
|
||||
SHA1 b88b6bad1e8cb0ba825594c233c006c1b297646f lib/Locale/Maketext/Gettext/Functions.pm
|
||||
SHA1 f89afd70fdcbaeeab44fada7ed3087d5c7f6f018 script/maketext
|
||||
SHA1 525f414c7a0aadc61240a4b0959ca2cda7514c75 t/00-signature.t
|
||||
SHA1 7bc2bf2d3ef2befd48a457fb3d90c7c7bdcc4854 t/01-basic.t
|
||||
SHA1 73ce1e3ba168373318655b3f4fbca1847e49fd75 t/02-big-endian.t
|
||||
SHA1 4b07656e4c35bfce793c96b59bb9ae2917be335e t/03-errors.t
|
||||
SHA1 8a28c721b5eefe607c300192c8cb8e8107f419be t/04-encodings.t
|
||||
SHA1 c16af7bbe1d9bd7ce8644c19f968231b94156c12 t/05-switching.t
|
||||
SHA1 0212e5b50d6886601b0a4ad82d3c656975009a73 t/06-racing.t
|
||||
SHA1 2ddb628b67ae35033fad4331c5323928d7dd7395 t/07-f-basic.t
|
||||
SHA1 a4491ef77b899c4988b8ab34fb8f945a8d06c285 t/08-f-errors.t
|
||||
SHA1 8fb7ecbce36daaf81ac9c197dab6834b25233cc5 t/09-f-encodings.t
|
||||
SHA1 2c1641cc6fff792fb83826486050acab23a1db51 t/10-f-switching.t
|
||||
SHA1 4afe4980e7ed4d326009b8257e01320abfb33d14 t/11-command-line.t
|
||||
SHA1 b85626024d610808bd0909989dcfb9fb20a40485 t/99-pod.t
|
||||
SHA1 97dad77dee7f751d09efdb6900b077d68c853d46 t/T_L10N.pm
|
||||
SHA1 676b87d7a8edc735ba676d2901827eb52532b418 t/locale/C/LC_MESSAGES/test.mo
|
||||
SHA1 80ca74a96bd6f83bd903ebfd021b87c9184582eb t/locale/en/LC_MESSAGES/bad.mo
|
||||
SHA1 676b87d7a8edc735ba676d2901827eb52532b418 t/locale/en/LC_MESSAGES/test.mo
|
||||
SHA1 fbd67646ebb39a99c1ab5aa985addd7f7ab27561 t/locale/en/LC_MESSAGES/test2.mo
|
||||
SHA1 99b05048a1243bb75622a3c6e8a7c8e9f59a9151 t/locale/en/LC_MESSAGES/test_be.mo
|
||||
SHA1 5d3e312b86526ebe164589b1f7fbf96f01823b0c t/locale/en/LC_MESSAGES/test_utf8.mo
|
||||
SHA1 42eece65e0ceae8267000b42692212c260a49b36 t/locale/zh_CN/LC_MESSAGES/test.mo
|
||||
SHA1 746c06a73e4eb641eb006c90ed938c4b98cfc2ec t/locale/zh_CN/LC_MESSAGES/test_be.mo
|
||||
SHA1 8db66e4035d1f55cd27186e02c0386709c2fc3d0 t/locale/zh_CN/LC_MESSAGES/test_utf8.mo
|
||||
SHA1 6aa98d6675c91555309d58a93ff59cb205cbdd7b t/locale/zh_TW/LC_MESSAGES/test.mo
|
||||
SHA1 bcc89cdc393507d51b5a76e40954db72914b60d8 t/locale/zh_TW/LC_MESSAGES/test2.mo
|
||||
SHA1 20f810c6229d0bd4064b27f9b3d86b61a20f0821 t/locale/zh_TW/LC_MESSAGES/test_be.mo
|
||||
SHA1 eb13887b005e3c3e9fab774dfea22de5c01ad1ef t/locale/zh_TW/LC_MESSAGES/test_utf8.mo
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.9 (GNU/Linux)
|
||||
|
||||
iEYEARECAAYFAkpFc8MACgkQi9gubzC5S1w3kQCfY4bdMI9M6+sTT+y//sHibPDP
|
||||
LUUAnRvtrXrg1Tov/anLHx0Xur3TmAQQ
|
||||
=Au1F
|
||||
-----END PGP SIGNATURE-----
|
24
THANKS
Normal file
24
THANKS
Normal file
@ -0,0 +1,24 @@
|
||||
Thanks to Sean M. Burke, for writing such a great localization framework as
|
||||
Locale::Maketext, especially for his ideas about the plural forms.
|
||||
|
||||
Thanks to the GNU group, for writing such a great localization framework as
|
||||
GNU gettext, especially for the completeness and simplicity of its design.
|
||||
|
||||
Thanks for Autrijus Tang <autrijus@autrijus.org> for writing
|
||||
Locale::Maketext::Lexicon. It inspires me to import %Lexicon from other
|
||||
sources. Also thanks for approving such a project that is a competition to
|
||||
his own Locale::Maketext::Lexicon. :p
|
||||
|
||||
Thanks to Max Maischein <corion@corion.net> for reporting CPAN tester failures
|
||||
200029, 200332 and 200331, that helps me finding the shell character escaping
|
||||
problem on my test suite.
|
||||
|
||||
Thanks to Andreas Koenig <andk@cpan.org> for reporting CPAN tester failures
|
||||
387357 and submitting rt bug 23956, informing me the base class
|
||||
Locale::Maketext has updated its error handling behavior in the Perl 5.9.
|
||||
|
||||
Thanks to Chris Travers <chris.travers@gmail.com> for suggestion on
|
||||
implementing pgettext() in GNU gettext as pmaketext().
|
||||
|
||||
Finally, well, :p thanks to Larry Wall, for writing such a
|
||||
great programming language, as Perl.
|
4
TODO
Normal file
4
TODO
Normal file
@ -0,0 +1,4 @@
|
||||
Locale-Maketext-Gettext TODO list
|
||||
|
||||
- Design a way for MO file installation through ExtUtils::MakeMaker
|
||||
and Module::Build.
|
814
lib/Locale/Maketext/Gettext.pm
Normal file
814
lib/Locale/Maketext/Gettext.pm
Normal file
@ -0,0 +1,814 @@
|
||||
# Locale::Maketext::Gettext - Joins the gettext and Maketext frameworks
|
||||
|
||||
# Copyright (c) 2003-2009 imacat. All rights reserved. This program is free
|
||||
# software; you can redistribute it and/or modify it under the same terms
|
||||
# as Perl itself.
|
||||
# First written: 2003-04-23
|
||||
|
||||
package Locale::Maketext::Gettext;
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use base qw(Locale::Maketext Exporter);
|
||||
use vars qw($VERSION @ISA %Lexicon @EXPORT @EXPORT_OK);
|
||||
$VERSION = 1.28;
|
||||
@EXPORT = qw(read_mo);
|
||||
@EXPORT_OK = @EXPORT;
|
||||
# Prototype declaration
|
||||
sub read_mo($);
|
||||
|
||||
use Encode qw(encode decode FB_DEFAULT);
|
||||
use File::Spec::Functions qw(catfile);
|
||||
no strict qw(refs);
|
||||
|
||||
use vars qw(%Lexicons %ENCODINGS $REREAD_MO $MOFILE);
|
||||
$REREAD_MO = 0;
|
||||
$MOFILE = "";
|
||||
use vars qw(@SYSTEM_LOCALEDIRS);
|
||||
@SYSTEM_LOCALEDIRS = qw(/usr/share/locale /usr/lib/locale
|
||||
/usr/local/share/locale /usr/local/lib/locale);
|
||||
|
||||
# encoding: Set or retrieve the output encoding
|
||||
sub encoding : method {
|
||||
local ($_, %_);
|
||||
my $self;
|
||||
($self, $_) = @_;
|
||||
|
||||
# This is not a static method
|
||||
return if ref($self) eq "";
|
||||
|
||||
# Set the output encoding
|
||||
if (@_ > 1) {
|
||||
if (defined $_) {
|
||||
$self->{"ENCODING"} = $_;
|
||||
} else {
|
||||
delete $self->{"ENCODING"};
|
||||
}
|
||||
$self->{"USERSET_ENCODING"} = $_;
|
||||
}
|
||||
|
||||
# Return the encoding
|
||||
return exists $self->{"ENCODING"}? $self->{"ENCODING"}: undef;
|
||||
}
|
||||
|
||||
# key_encoding: Specify the encoding used in the keys
|
||||
sub key_encoding : method {
|
||||
local ($_, %_);
|
||||
my $self;
|
||||
($self, $_) = @_;
|
||||
|
||||
# This is not a static method
|
||||
return if ref($self) eq "";
|
||||
|
||||
# Set the encoding used in the keys
|
||||
if (@_ > 1) {
|
||||
if (defined $_) {
|
||||
$self->{"KEY_ENCODING"} = $_;
|
||||
} else {
|
||||
delete $self->{"KEY_ENCODING"};
|
||||
}
|
||||
}
|
||||
|
||||
# Return the encoding
|
||||
return exists $self->{"KEY_ENCODING"}? $self->{"KEY_ENCODING"}: undef;
|
||||
}
|
||||
|
||||
# new: Initialize the language handler
|
||||
sub new : method {
|
||||
local ($_, %_);
|
||||
my ($self, $class);
|
||||
$class = ref($_[0]) || $_[0];
|
||||
$self = bless {}, $class;
|
||||
$self->subclass_init;
|
||||
$self->init;
|
||||
return $self;
|
||||
}
|
||||
|
||||
# subclass_init: Initialize at the subclass level, so that it can be
|
||||
# inherited by calling $self->SUPER:subclass_init
|
||||
sub subclass_init : method {
|
||||
local ($_, %_);
|
||||
my ($self, $class);
|
||||
$self = $_[0];
|
||||
$class = ref($self);
|
||||
# Initialize the instance lexicon
|
||||
$self->{"Lexicon"} = {};
|
||||
# Initialize the LOCALEDIRS registry
|
||||
$self->{"LOCALEDIRS"} = {};
|
||||
# Initialize the MO timestamp
|
||||
$self->{"REREAD_MO"} = $REREAD_MO;
|
||||
# Initialize the DIE_FOR_LOOKUP_FAILURES setting
|
||||
$self->{"DIE_FOR_LOOKUP_FAILURES"} = 0;
|
||||
$self->SUPER::fail_with($self->can("failure_handler_auto"));
|
||||
# Initialize the ENCODE_FAILURE setting
|
||||
$self->{"ENCODE_FAILURE"} = FB_DEFAULT;
|
||||
# Initialize the MOFILE value of this instance
|
||||
$self->{"MOFILE"} = "";
|
||||
${"$class\::MOFILE"} = "" if !defined ${"$class\::MOFILE"};
|
||||
# Find the locale name, for this subclass
|
||||
$self->{"LOCALE"} = $class;
|
||||
$self->{"LOCALE"} =~ s/^.*:://;
|
||||
$self->{"LOCALE"} =~ s/(_)(.*)$/$1 . uc $2/e;
|
||||
# Map i_default to C
|
||||
$self->{"LOCALE"} = "C" if $self->{"LOCALE"} eq "i_default";
|
||||
# Set the category. Currently this is always LC_MESSAGES
|
||||
$self->{"CATEGORY"} = "LC_MESSAGES";
|
||||
# Default key encoding is US-ASCII
|
||||
$self->{"KEY_ENCODING"} = "US-ASCII";
|
||||
return;
|
||||
}
|
||||
|
||||
# bindtextdomain: Bind a text domain to a locale directory
|
||||
sub bindtextdomain : method {
|
||||
local ($_, %_);
|
||||
my ($self, $DOMAIN, $LOCALEDIR);
|
||||
($self, $DOMAIN, $LOCALEDIR) = @_;
|
||||
|
||||
# This is not a static method
|
||||
return if ref($self) eq "";
|
||||
|
||||
# Return null for this rare case
|
||||
return if !defined $LOCALEDIR
|
||||
&& !exists ${$self->{"LOCALEDIRS"}}{$DOMAIN};
|
||||
|
||||
# Register the DOMAIN and its LOCALEDIR
|
||||
${$self->{"LOCALEDIRS"}}{$DOMAIN} = $LOCALEDIR if defined $LOCALEDIR;
|
||||
|
||||
# Return the registry
|
||||
return ${$self->{"LOCALEDIRS"}}{$DOMAIN};
|
||||
}
|
||||
|
||||
# textdomain: Set the current text domain
|
||||
sub textdomain : method {
|
||||
local ($_, %_);
|
||||
my ($self, $class, $DOMAIN, $LOCALEDIR, $MOfile);
|
||||
($self, $DOMAIN) = @_;
|
||||
|
||||
# This is not a static method
|
||||
return if ref($self) eq "";
|
||||
# Find the class name
|
||||
$class = ref($self);
|
||||
|
||||
# Return the current domain
|
||||
return $self->{"DOMAIN"} if !defined $DOMAIN;
|
||||
|
||||
# Set the timestamp of this read in this instance
|
||||
$self->{"REREAD_MO"} = $REREAD_MO;
|
||||
# Set the current domain
|
||||
$self->{"DOMAIN"} = $DOMAIN;
|
||||
|
||||
# Clear it
|
||||
$self->{"Lexicon"} = {};
|
||||
%{"$class\::Lexicon"} = qw();
|
||||
$self->{"MOFILE"} = "";
|
||||
${"$class\::MOFILE"} = "";
|
||||
|
||||
# The format is "{LOCALEDIR}/{LOCALE}/{CATEGORY}/{DOMAIN}.mo"
|
||||
# Search the system locale directories if the domain was not
|
||||
# registered yet
|
||||
if (!exists ${$self->{"LOCALEDIRS"}}{$DOMAIN}) {
|
||||
undef $MOfile;
|
||||
foreach $LOCALEDIR (@SYSTEM_LOCALEDIRS) {
|
||||
$_ = catfile($LOCALEDIR, $self->{"LOCALE"},
|
||||
$self->{"CATEGORY"}, "$DOMAIN.mo");
|
||||
if (-f $_ && -r $_) {
|
||||
$MOfile = $_;
|
||||
last;
|
||||
}
|
||||
}
|
||||
# Not found at last
|
||||
return $DOMAIN if !defined $MOfile;
|
||||
|
||||
# This domain was registered
|
||||
} else {
|
||||
$MOfile = catfile(${$self->{"LOCALEDIRS"}}{$DOMAIN},
|
||||
$self->{"LOCALE"}, $self->{"CATEGORY"}, "$DOMAIN.mo");
|
||||
}
|
||||
|
||||
# Record it
|
||||
${"$class\::MOFILE"} = $MOfile;
|
||||
$self->{"MOFILE"} = $MOfile;
|
||||
|
||||
# Read the MO file
|
||||
# Cached
|
||||
if (!exists $ENCODINGS{$MOfile} || !exists $Lexicons{$MOfile}) {
|
||||
my $enc;
|
||||
# Read it
|
||||
%_ = read_mo($MOfile);
|
||||
|
||||
# Successfully read
|
||||
if (scalar(keys %_) > 0) {
|
||||
# Decode it
|
||||
# Find the encoding of that MO file
|
||||
if ($_{""} =~ /^Content-Type: text\/plain; charset=(.*)$/im) {
|
||||
$enc = $1;
|
||||
# Default to US-ASCII
|
||||
} else {
|
||||
$enc = "US-ASCII";
|
||||
}
|
||||
# Set the current encoding to the encoding of the MO file
|
||||
$_{$_} = decode($enc, $_{$_}) foreach keys %_;
|
||||
}
|
||||
|
||||
# Cache them
|
||||
$Lexicons{$MOfile} = \%_;
|
||||
$ENCODINGS{$MOfile} = $enc;
|
||||
}
|
||||
|
||||
# Respect the existing output encoding
|
||||
if (defined $ENCODINGS{$MOfile}) {
|
||||
$self->{"MO_ENCODING"} = $ENCODINGS{$MOfile};
|
||||
} else {
|
||||
delete $self->{"MO_ENCODING"};
|
||||
}
|
||||
# Respect the MO file encoding unless there is a user preferrence
|
||||
if (!exists $self->{"USERSET_ENCODING"}) {
|
||||
if (exists $self->{"MO_ENCODING"}) {
|
||||
$self->{"ENCODING"} = $self->{"MO_ENCODING"};
|
||||
} else {
|
||||
delete $self->{"ENCODING"};
|
||||
}
|
||||
}
|
||||
$self->{"Lexicon"} = $Lexicons{$MOfile};
|
||||
%{"$class\::Lexicon"} = %{$Lexicons{$MOfile}};
|
||||
$self->clear_isa_scan;
|
||||
|
||||
return $DOMAIN;
|
||||
}
|
||||
|
||||
# maketext: Encode after maketext
|
||||
sub maketext : method {
|
||||
local ($_, %_);
|
||||
my ($self, $key, @param, $class, $keyd);
|
||||
($self, $key, @param) = @_;
|
||||
|
||||
# This is not a static method - NOW
|
||||
return if ref($self) eq "";
|
||||
# Find the class name
|
||||
$class = ref($self);
|
||||
|
||||
# MO file should be re-read
|
||||
if ($self->{"REREAD_MO"} < $REREAD_MO) {
|
||||
$self->{"REREAD_MO"} = $REREAD_MO;
|
||||
defined($_ = $self->textdomain) and $self->textdomain($_);
|
||||
}
|
||||
|
||||
# If the instance lexicon is changed.
|
||||
# Maketext uses a class lexicon. We have to copy the instance
|
||||
# lexicon into the class lexicon. This is slow. Mass memory
|
||||
# copy sucks. Avoid create several language handles for a
|
||||
# single localization subclass whenever possible.
|
||||
# Maketext uses class lexicon in order to track the inheritance.
|
||||
# It is hard to change it.
|
||||
if (${"$class\::MOFILE"} ne $self->{"MOFILE"}) {
|
||||
${"$class\::MOFILE"} = $self->{"MOFILE"};
|
||||
%{"$class\::Lexicon"} = %{$self->{"Lexicon"}};
|
||||
}
|
||||
|
||||
# Decode the source text
|
||||
$keyd = $key;
|
||||
$keyd = decode($self->{"KEY_ENCODING"}, $keyd, $self->{"ENCODE_FAILURE"})
|
||||
if exists $self->{"KEY_ENCODING"} && !Encode::is_utf8($key);
|
||||
# Maketext
|
||||
$_ = $self->SUPER::maketext($keyd, @param);
|
||||
# Output to the requested encoding
|
||||
if (exists $self->{"ENCODING"}) {
|
||||
$_ = encode($self->{"ENCODING"}, $_, $self->{"ENCODE_FAILURE"});
|
||||
# Pass through the empty/invalid lexicon
|
||||
} elsif ( scalar(keys %{$self->{"Lexicon"}}) == 0
|
||||
&& exists $self->{"KEY_ENCODING"}
|
||||
&& !Encode::is_utf8($key)) {
|
||||
$_ = encode($self->{"KEY_ENCODING"}, $_, $self->{"ENCODE_FAILURE"});
|
||||
}
|
||||
|
||||
return $_;
|
||||
}
|
||||
|
||||
# pmaketext: Maketext with context
|
||||
sub pmaketext : method {
|
||||
local ($_, %_);
|
||||
my ($self, $ctxt, $key, @param);
|
||||
($self, $ctxt, $key, @param) = @_;
|
||||
# This is not a static method - NOW
|
||||
return if ref($self) eq "";
|
||||
# This is actually a wrapper to the maketext() method
|
||||
return $self->maketext("$ctxt\x04$key", @param);
|
||||
}
|
||||
|
||||
# read_mo: Subroutine to read and parse the MO file
|
||||
# Refer to gettext documentation section 8.3
|
||||
sub read_mo($) {
|
||||
local ($_, %_);
|
||||
my ($MOfile, $len, $FH, $content, $tmpl);
|
||||
$MOfile = $_[0];
|
||||
|
||||
# Avild being stupid
|
||||
return unless -f $MOfile && -r $MOfile;
|
||||
# Read the MO file
|
||||
$len = (stat $MOfile)[7];
|
||||
open $FH, $MOfile or return; # GNU gettext never fails!
|
||||
binmode $FH;
|
||||
defined($_ = read $FH, $content, $len)
|
||||
or return;
|
||||
close $FH or return;
|
||||
|
||||
# Find the byte order of the MO file creator
|
||||
$_ = substr($content, 0, 4);
|
||||
# Little endian
|
||||
if ($_ eq "\xde\x12\x04\x95") {
|
||||
$tmpl = "V";
|
||||
# Big endian
|
||||
} elsif ($_ eq "\x95\x04\x12\xde") {
|
||||
$tmpl = "N";
|
||||
# Wrong magic number. Not a valid MO file.
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
# Check the MO format revision number
|
||||
$_ = unpack $tmpl, substr($content, 4, 4);
|
||||
# There is only one revision now: revision 0.
|
||||
return if $_ > 0;
|
||||
|
||||
my ($num, $offo, $offt);
|
||||
# Number of messages
|
||||
$num = unpack $tmpl, substr($content, 8, 4);
|
||||
# Offset to the beginning of the original messages
|
||||
$offo = unpack $tmpl, substr($content, 12, 4);
|
||||
# Offset to the beginning of the translated messages
|
||||
$offt = unpack $tmpl, substr($content, 16, 4);
|
||||
%_ = qw();
|
||||
for ($_ = 0; $_ < $num; $_++) {
|
||||
my ($len, $off, $stro, $strt);
|
||||
# The first word is the length of the message
|
||||
$len = unpack $tmpl, substr($content, $offo+$_*8, 4);
|
||||
# The second word is the offset of the message
|
||||
$off = unpack $tmpl, substr($content, $offo+$_*8+4, 4);
|
||||
# Original message
|
||||
$stro = substr($content, $off, $len);
|
||||
|
||||
# The first word is the length of the message
|
||||
$len = unpack $tmpl, substr($content, $offt+$_*8, 4);
|
||||
# The second word is the offset of the message
|
||||
$off = unpack $tmpl, substr($content, $offt+$_*8+4, 4);
|
||||
# Translated message
|
||||
$strt = substr($content, $off, $len);
|
||||
|
||||
# Hash it
|
||||
$_{$stro} = $strt;
|
||||
}
|
||||
|
||||
return %_;
|
||||
}
|
||||
|
||||
# reload_text: Method to purge the lexicon cache
|
||||
sub reload_text : method {
|
||||
local ($_, %_);
|
||||
|
||||
# Purge the text cache
|
||||
%Lexicons = qw();
|
||||
%ENCODINGS = qw();
|
||||
$REREAD_MO = time;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# fail_with: A wrapper to the fail_with() of Locale::Maketext, in order
|
||||
# to record the preferred failure handler of the user, so that
|
||||
# die_for_lookup_failures() knows where to return to.
|
||||
sub fail_with : method {
|
||||
local ($_, %_);
|
||||
my $self;
|
||||
($self, $_) = @_;
|
||||
|
||||
# This is not a static method
|
||||
return if ref($self) eq "";
|
||||
|
||||
# Set the current setting
|
||||
if (@_ > 1) {
|
||||
if (defined $_) {
|
||||
$self->{"USERSET_FAIL"} = $_;
|
||||
$self->SUPER::fail_with($_) if $self->{"DIE_FOR_LOOKUP_FAILURES"};
|
||||
} else {
|
||||
delete $self->{"USERSET_FAIL"};
|
||||
delete $self->{"fail"} if $self->{"DIE_FOR_LOOKUP_FAILURES"};
|
||||
}
|
||||
}
|
||||
|
||||
# Return the current setting
|
||||
return exists $self->{"USERSET_FAIL"}? $self->{"USERSET_FAIL"}: undef;
|
||||
}
|
||||
|
||||
# die_for_lookup_failures: Whether we should die for lookup failure
|
||||
# The default is no. GNU gettext never fails.
|
||||
sub die_for_lookup_failures : method {
|
||||
local ($_, %_);
|
||||
my $self;
|
||||
($self, $_) = @_;
|
||||
|
||||
# This is not a static method
|
||||
return if ref($self) eq "";
|
||||
|
||||
# Set the current setting
|
||||
if (@_ > 1) {
|
||||
if ($_) {
|
||||
$self->{"DIE_FOR_LOOKUP_FAILURES"} = 1;
|
||||
if (exists $self->{"USERSET_FAIL"}) {
|
||||
$self->{"fail"} = $self->{"USERSET_FAIL"};
|
||||
} else {
|
||||
delete $self->{"fail"};
|
||||
}
|
||||
} else {
|
||||
$self->SUPER::fail_with($self->can("failure_handler_auto"));
|
||||
$self->{"DIE_FOR_LOOKUP_FAILURES"} = 0;
|
||||
}
|
||||
}
|
||||
|
||||
# Return the current setting
|
||||
return exists $self->{"DIE_FOR_LOOKUP_FAILURES"}?
|
||||
$self->{"DIE_FOR_LOOKUP_FAILURES"}: undef;
|
||||
}
|
||||
|
||||
# encode_failure: What to do if the text is out of your output encoding
|
||||
# Refer to Encode on possible values of this check
|
||||
sub encode_failure : method {
|
||||
local ($_, %_);
|
||||
my $self;
|
||||
($self, $_) = @_;
|
||||
|
||||
# This is not a static method
|
||||
return if ref($self) eq "";
|
||||
|
||||
# Specify the action used in the keys
|
||||
$self->{"ENCODE_FAILURE"} = $_ if @_ > 1;
|
||||
|
||||
# Return the encoding
|
||||
return $self->{"ENCODE_FAILURE"} if exists $self->{"ENCODE_FAILURE"};
|
||||
return undef;
|
||||
}
|
||||
|
||||
# failure_handler_auto: Our local version of failure_handler_auto(),
|
||||
# Copied and rewritten from Locale::Maketext, with bug#33938 patch applied.
|
||||
# See http://rt.perl.org/rt3//Public/Bug/Display.html?id=33938
|
||||
sub failure_handler_auto : method {
|
||||
local ($_, %_);
|
||||
my ($self, $key, @param, $r);
|
||||
($self, $key, @param) = @_;
|
||||
|
||||
# This is not a static method
|
||||
return if ref($self) eq "";
|
||||
|
||||
# Remove the context
|
||||
# We assume there is no one using EOF either in the context or message.
|
||||
# That does not work in GNU gettext, anyway.
|
||||
$key =~ s/^[^\x04]*\x04//;
|
||||
|
||||
$self->{"failure_lex"} = {} if !exists $self->{"failure_lex"};
|
||||
${$self->{"failure_lex"}}{$key} = $self->_compile($key)
|
||||
if !exists ${$self->{"failure_lex"}}{$key};
|
||||
$_ = ${$self->{"failure_lex"}}{$key};
|
||||
|
||||
# A scalar result
|
||||
return $$_ if ref($_) eq "SCALAR";
|
||||
return $_ unless ref($_) eq "CODE";
|
||||
# A compiled subroutine
|
||||
{
|
||||
local $SIG{"__DIE__"};
|
||||
$r = eval {
|
||||
$_ = &$_($self, @param);
|
||||
return 1;
|
||||
};
|
||||
}
|
||||
|
||||
# If we make it here, there was an exception thrown in the
|
||||
# call to $value, and so scream:
|
||||
if (!defined $r) {
|
||||
$_ = $@;
|
||||
# pretty up the error message
|
||||
s<\s+at\s+\(eval\s+\d+\)\s+line\s+(\d+)\.?\n?>
|
||||
<\n in bracket code [compiled line $1],>s;
|
||||
Carp::croak "Error in maketexting \"$key\":\n$_ as used";
|
||||
return;
|
||||
}
|
||||
|
||||
# OK
|
||||
return $_;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Locale::Maketext::Gettext - Joins the gettext and Maketext frameworks
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
In your localization class:
|
||||
|
||||
package MyPackage::L10N;
|
||||
use base qw(Locale::Maketext::Gettext);
|
||||
return 1;
|
||||
|
||||
In your application:
|
||||
|
||||
use MyPackage::L10N;
|
||||
$LH = MyPackage::L10N->get_handle or die "What language?";
|
||||
$LH->bindtextdomain("mypackage", "/home/user/locale");
|
||||
$LH->textdomain("mypackage");
|
||||
$LH->maketext("Hello, world!!");
|
||||
|
||||
If you want to have more control to the detail:
|
||||
|
||||
# Change the output encoding
|
||||
$LH->encoding("UTF-8");
|
||||
# Stick with the Maketext behavior on lookup failures
|
||||
$LH->die_for_lookup_failures(1);
|
||||
# Flush the MO file cache and re-read your updated MO files
|
||||
$LH->reload_text;
|
||||
# Set the encoding of your maketext keys, if not in English
|
||||
$LH->key_encoding("Big5");
|
||||
# Set the action when encode fails
|
||||
$LH->encode_failure(Encode::FB_HTMLCREF);
|
||||
|
||||
Use Locale::Maketext::Gettext to read and parse the MO file:
|
||||
|
||||
use Locale::Maketext::Gettext;
|
||||
%Lexicon = read_mo($MOfile);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Locale::Maketext::Gettext joins the GNU gettext and Maketext
|
||||
frameworks. It is a subclass of L<Locale::Maketext(3)|Locale::Maketext/3>
|
||||
that follows the way GNU gettext works. It works seamlessly, I<both
|
||||
in the sense of GNU gettext and Maketext>. As a result, you I<enjoy
|
||||
both their advantages, and get rid of both their problems, too.>
|
||||
|
||||
You start as an usual GNU gettext localization project: Work on
|
||||
PO files with the help of translators, reviewers and Emacs. Turn
|
||||
them into MO files with F<msgfmt>. Copy them into the appropriate
|
||||
locale directory, such as
|
||||
F</usr/share/locale/de/LC_MESSAGES/myapp.mo>.
|
||||
|
||||
Then, build your Maketext localization class, with your base class
|
||||
changed from L<Locale::Maketext(3)|Locale::Maketext/3> to
|
||||
Locale::Maketext::Gettext. That is all.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=over
|
||||
|
||||
=item $LH->bindtextdomain(DOMAIN, LOCALEDIR)
|
||||
|
||||
Register a text domain with a locale directory. Returns C<LOCALEDIR>
|
||||
itself. If C<LOCALEDIR> is omitted, the registered locale directory
|
||||
of C<DOMAIN> is returned. This method always success.
|
||||
|
||||
=item $LH->textdomain(DOMAIN)
|
||||
|
||||
Set the current text domain. Returns the C<DOMAIN> itself. If
|
||||
C<DOMAIN> is omitted, the current text domain is returned. This
|
||||
method always success.
|
||||
|
||||
=item $text = $LH->maketext($key, @param...)
|
||||
|
||||
Lookup the $key in the current lexicon and return a translated
|
||||
message in the language of the user. This is the same method in
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3>, with a wrapper that
|
||||
returns the text message C<encode>d according to the current
|
||||
C<encoding>. Refer to L<Locale::Maketext(3)|Locale::Maketext/3> for
|
||||
the maketext plural notation.
|
||||
|
||||
=item $text = $LH->pmaketext($ctxt, $key, @param...)
|
||||
|
||||
Lookup the $key in a particular context in the current lexicon and
|
||||
return a translated message in the language of the user. Use
|
||||
"--keyword=pmaketext:1c,2" for the xgettext utility.
|
||||
|
||||
=item $LH->language_tag
|
||||
|
||||
Retrieve the language tag. This is the same method in
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3>. It is readonly.
|
||||
|
||||
=item $LH->encoding(ENCODING)
|
||||
|
||||
Set or retrieve the output encoding. The default is the same
|
||||
encoding as the gettext MO file. You can specify C<undef>, to return
|
||||
the result in unencoded UTF-8.
|
||||
|
||||
=item $LH->key_encoding(ENCODING)
|
||||
|
||||
Specify the encoding used in your original text. The C<maketext>
|
||||
method itself is not multibyte-safe to the _AUTO lexicon. If you are
|
||||
using your native non-English language as your original text and you
|
||||
are having troubles like:
|
||||
|
||||
Unterminated bracket group, in:
|
||||
|
||||
Then, specify the C<key_encoding> to the encoding of your original
|
||||
text. Returns the current setting.
|
||||
|
||||
B<WARNING:> You should always use US-ASCII text keys. Using
|
||||
non-US-ASCII keys is always discouraged and is not guaranteed to
|
||||
be working.
|
||||
|
||||
=item $LH->encode_failure(CHECK)
|
||||
|
||||
Set the action when encode fails. This happens when the output text
|
||||
is out of the scope of your output encoding. For exmaple, output
|
||||
Chinese into US-ASCII. Refer to L<Encode(3)|Encode/3> for the
|
||||
possible values of this C<CHECK>. The default is C<FB_DEFAULT>,
|
||||
which is a safe choice that never fails. But part of your text may
|
||||
be lost, since that is what C<FB_DEFAULT> does. Returns the current
|
||||
setting.
|
||||
|
||||
=item $LH->die_for_lookup_failures(SHOULD_I_DIE)
|
||||
|
||||
Maketext dies for lookup failures, but GNU gettext never fails.
|
||||
By default Lexicon::Maketext::Gettext follows the GNU gettext
|
||||
behavior. But if you are Maketext-styled, or if you need a better
|
||||
control over the failures (like me :p), set this to 1. Returns the
|
||||
current setting.
|
||||
|
||||
Note that lookup failure handler you registered with fail_with() only
|
||||
work when die_for_lookup_failures() is enabled. if you disable
|
||||
die_for_lookup_failures(), maketext() never fails and lookup failure
|
||||
handler will be ignored.
|
||||
|
||||
=item $LH->reload_text
|
||||
|
||||
Purge the MO text cache. It purges the MO text cache from the base
|
||||
class Locale::Maketext::Gettext. The next time C<maketext> is
|
||||
called, the MO file will be read and parse from the disk again. This
|
||||
is used when your MO file is updated, but you cannot shutdown and
|
||||
restart the application. For example, when you are a co-hoster on a
|
||||
mod_perl-enabled Apache, or when your mod_perl-enabled Apache is too
|
||||
vital to be restarted for every update of your MO file, or if you
|
||||
are running a vital daemon, such as an X display server.
|
||||
|
||||
=back
|
||||
|
||||
=head1 FUNCTIONS
|
||||
|
||||
=over
|
||||
|
||||
=item %Lexicon = read_mo($MOfile);
|
||||
|
||||
Read and parse the MO file. Returns the read %Lexicon. The returned
|
||||
lexicon is in its original encoding.
|
||||
|
||||
If you need the meta infomation of your MO file, parse the entry
|
||||
C<$Lexicon{""}>. For example:
|
||||
|
||||
/^Content-Type: text\/plain; charset=(.*)$/im;
|
||||
$encoding = $1;
|
||||
|
||||
C<read_mo()> is exported by default, but you need to C<use
|
||||
Locale::Maketext::Gettext> in order to use it. It is not exported
|
||||
from your localization class, but from the Locale::Maketext::Gettext
|
||||
package.
|
||||
|
||||
=back
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
B<WARNING:> do not try to put any lexicon in your language subclass.
|
||||
When the C<textdomain> method is called, the current lexicon will be
|
||||
B<replaced>, but not appended. This is to accommodate the way
|
||||
C<textdomain> works. Messages from the previous text domain should
|
||||
not stay in the current text domain.
|
||||
|
||||
An essential benefit of this Locale::Maketext::Gettext over the
|
||||
original L<Locale::Maketext(3)|Locale::Maketext/3> is that:
|
||||
I<GNU gettext is multibyte safe,> but Perl source is not. GNU gettext
|
||||
is safe to Big5 characters like \xa5\x5c (Gong1). But if you follow
|
||||
the current L<Locale::Maketext(3)|Locale::Maketext/3> document and
|
||||
put your lexicon as a hash in the source of a localization subclass,
|
||||
you have to escape bytes like \x5c, \x40, \x5b, etc., in the middle
|
||||
of some natural multibyte characters. This breaks these characters
|
||||
in halves. Your non-technical translators and reviewers will be
|
||||
presented with unreadable mess, "Luan4Ma3". Sorry to say this, but
|
||||
it is weird for a localization framework to be not multibyte-safe.
|
||||
But, well, here comes Locale::Maketext::Gettext to rescue. With
|
||||
Locale::Maketext::Gettext, you can sit back and relax now, leaving
|
||||
all this mess to the excellent GNU gettext framework.
|
||||
|
||||
The idea of Locale::Maketext::Getttext came from
|
||||
L<Locale::Maketext::Lexicon(3)|Locale::Maketext::Lexicon/3>, a great
|
||||
work by Autrijus. But it has several problems at that time (version
|
||||
0.16). I was first trying to write a wrapper to fix it, but finally
|
||||
I dropped it and decided to make a solution towards
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3> itself.
|
||||
L<Locale::Maketext::Lexicon(3)|Locale::Maketext::Lexicon/3> should be
|
||||
fine now if you obtain a version newer than 0.16.
|
||||
|
||||
Locale::Maketext::Gettext also solved the problem of lack of the
|
||||
ability to handle the encoding in
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3>. I implement this since
|
||||
this is what GNU gettext does. When %Lexicon is read from MO files
|
||||
by C<read_mo()>, the encoding tagged in gettext MO files is used to
|
||||
C<decode> the text into the internal encoding of Perl. Then, when
|
||||
extracted by C<maketext>, it is C<encode>d by the current
|
||||
C<encoding> value. The C<encoding> can be set at run time, so
|
||||
that you can run a daemon and output to different encoding
|
||||
according to the language settings of individual users, without
|
||||
having to restart the application. This is an improvement to the
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3>, and is essential to
|
||||
daemons and C<mod_perl> applications.
|
||||
|
||||
You should trust the encoding of your gettext MO file. GNU gettext
|
||||
C<msgfmt> checks the illegal characters for you when you compile your
|
||||
MO file from your PO file. The encoding form your MO files are
|
||||
always good. If you try to output to a wrong encoding, part of your
|
||||
text may be lost, as C<FB_DEFAULT> does. If you do not like this
|
||||
C<FB_DEFAULT>, change the failure behavior with the method
|
||||
C<encode_failure>.
|
||||
|
||||
If you need the behavior of auto Traditional Chinese/Simplfied
|
||||
Chinese conversion, as GNU gettext smartly does, do it yourself with
|
||||
L<Encode::HanExtra(3)|Encode::HanExtra/3>, too. There may be a
|
||||
solution for this in the future, but not now.
|
||||
|
||||
If you set C<textdomain> to a domain that is not C<bindtextdomain> to
|
||||
specific a locale directory yet, it will try search system locale
|
||||
directories. The current system locale directory search order is:
|
||||
/usr/share/locale, /usr/lib/locale, /usr/local/share/locale,
|
||||
/usr/local/lib/locale. Suggestions for this search order are
|
||||
welcome.
|
||||
|
||||
B<NOTICE:> I<MyPackage::L10N::en-E<gt>maketext(...) is not available
|
||||
anymore,> as the C<maketext> method is no more static. That is a
|
||||
sure result, as %Lexicon is imported from foreign sources
|
||||
dynamically, but not statically hardcoded in Perl sources. But the
|
||||
documentation of L<Locale::Maketext(3)|Locale::Maketext/3> does not
|
||||
say that you can use it as a static method anyway. Maybe you were
|
||||
practicing this before. You had better check your existing code for
|
||||
this. If you try to invoke it statically, it returns C<undef>.
|
||||
|
||||
C<dgettext> and C<dcgettext> in GNU gettext are not implemented.
|
||||
It is not possible to temporarily change the current text domain in
|
||||
the current design of Locale::Maketext::Gettext. Besides, it is
|
||||
meaningless. Locale::Maketext is object-oriented. You can always
|
||||
raise a new language handle for another text domain. This is
|
||||
different from the situation of GNU gettext. Also, the category
|
||||
is always C<LC_MESSAGES>. Of course it is. We are gettext and
|
||||
Maketext.
|
||||
|
||||
Avoid creating different language handles with different
|
||||
textdomain on the same localization subclass. This currently
|
||||
works, but it violates the basic design of
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3>. In
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3>, %Lexicon is saved as a
|
||||
class variable, in order for the lexicon inheritance system to work.
|
||||
So, multiple language handles to a same localization subclass shares
|
||||
a same lexicon space. Their lexicon space clash. I tried to avoid
|
||||
this problem by saving a copy of the current lexicon as an instance
|
||||
variable, and replacing the class lexicon with the current instance
|
||||
lexicon whenever it is changed by another language handle instance.
|
||||
But this involves large scaled memory copy, which affects the
|
||||
proformance seriously. This is discouraged. You are adviced to use
|
||||
a single textdomain for a single localization class.
|
||||
|
||||
The C<key_encoding> is a workaround, not a solution. There is no
|
||||
solution to this problem yet. You should avoid using non-English
|
||||
language as your original text. You will get yourself into trouble
|
||||
if you mix several original text encodings, for example, joining
|
||||
several pieces of code from programmers all around the world, with
|
||||
their messages written in their own language and encodings. Solution
|
||||
suggestions are welcome.
|
||||
|
||||
C<pgettext> in GNU gettext is implemented as C<pmaketext>, in order
|
||||
to look up the text message translation in a particular context.
|
||||
Thanks to the suggestion from Chris Travers.
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
GNU gettext never fails. I tries to achieve it as long as possible.
|
||||
The only reason that maketext may die unexpectedly now is
|
||||
"Unterminated bracket group". I cannot get a better solution to it
|
||||
currently. Suggestions are welcome.
|
||||
|
||||
You are welcome to fix my English. I have done my best to this
|
||||
documentation, but I am not a native English speaker after all. ^^;
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3>,
|
||||
L<Locale::Maketext::TPJ13(3)|Locale::Maketext::TPJ13/3>,
|
||||
L<Locale::Maketext::Lexicon(3)|Locale::Maketext::Lexicon/3>,
|
||||
L<Encode(3)|Encode/3>, L<bindtextdomain(3)|bindtextdomain/3>,
|
||||
L<textdomain(3)|textdomain/3>. Also, please refer to the official GNU
|
||||
gettext manual at L<http://www.gnu.org/software/gettext/manual/>.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
imacat <imacat@mail.imacat.idv.tw>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (c) 2003-2008 imacat. All rights reserved. This program is free
|
||||
software; you can redistribute it and/or modify it under the same terms
|
||||
as Perl itself.
|
||||
|
||||
=cut
|
781
lib/Locale/Maketext/Gettext/Functions.pm
Normal file
781
lib/Locale/Maketext/Gettext/Functions.pm
Normal file
@ -0,0 +1,781 @@
|
||||
# Locale::Maketext::Gettext::Functions - Functional interface to Locale::Maketext::Gettext
|
||||
|
||||
# Copyright (c) 2003-2008 imacat. All rights reserved. This program is free
|
||||
# software; you can redistribute it and/or modify it under the same terms
|
||||
# as Perl itself.
|
||||
# First written: 2003-04-28
|
||||
|
||||
package Locale::Maketext::Gettext::Functions;
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use base qw(Exporter);
|
||||
use vars qw($VERSION @EXPORT @EXPORT_OK);
|
||||
$VERSION = 0.13;
|
||||
@EXPORT = qw();
|
||||
push @EXPORT, qw(bindtextdomain textdomain get_handle maketext __ N_);
|
||||
push @EXPORT, qw(dmaketext pmaketext dpmaketext);
|
||||
push @EXPORT, qw(reload_text read_mo encoding key_encoding encode_failure);
|
||||
push @EXPORT, qw(die_for_lookup_failures);
|
||||
@EXPORT_OK = @EXPORT;
|
||||
# Prototype declaration
|
||||
sub bindtextdomain($;$);
|
||||
sub textdomain(;$);
|
||||
sub get_handle(@);
|
||||
sub maketext(@);
|
||||
sub __(@);
|
||||
sub N_(@);
|
||||
sub dmaketext($$@);
|
||||
sub pmaketext($$@);
|
||||
sub dpmaketext($$$@);
|
||||
sub reload_text();
|
||||
sub encoding(;$);
|
||||
sub key_encoding(;$);
|
||||
sub encode_failure(;$);
|
||||
sub die_for_lookup_failures(;$);
|
||||
sub _declare_class($);
|
||||
sub _catclass(@);
|
||||
sub _init_textdomain($);
|
||||
sub _get_langs($$);
|
||||
sub _get_handle();
|
||||
sub _get_empty_handle();
|
||||
sub _reset();
|
||||
sub _new_rid();
|
||||
sub _k($);
|
||||
sub _lang($);
|
||||
|
||||
use Encode qw(encode decode from_to FB_DEFAULT);
|
||||
use File::Spec::Functions qw(catdir catfile);
|
||||
use Locale::Maketext::Gettext qw(read_mo);
|
||||
use vars qw(%LOCALEDIRS %RIDS %CLASSES %LANGS);
|
||||
use vars qw(%LHS $_EMPTY $LH $DOMAIN $CATEGORY $CLASSBASE @LANGS %PARAMS);
|
||||
use vars qw(@SYSTEM_LOCALEDIRS);
|
||||
%LHS = qw();
|
||||
# The category is always LC_MESSAGES
|
||||
$CATEGORY = "LC_MESSAGES";
|
||||
$CLASSBASE = "Locale::Maketext::Gettext::_runtime";
|
||||
# Current language parameters
|
||||
@LANGS = qw();
|
||||
@SYSTEM_LOCALEDIRS = @Locale::Maketext::Gettext::SYSTEM_LOCALEDIRS;
|
||||
%PARAMS = qw();
|
||||
$PARAMS{"KEY_ENCODING"} = "US-ASCII";
|
||||
$PARAMS{"ENCODE_FAILURE"} = FB_DEFAULT;
|
||||
$PARAMS{"DIE_FOR_LOOKUP_FAILURES"} = 0;
|
||||
# Parameters for random class IDs
|
||||
use vars qw($RID_LEN @RID_CHARS);
|
||||
$RID_LEN = 8;
|
||||
@RID_CHARS = split //,
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
# bindtextdomain: Bind a text domain to a locale directory
|
||||
sub bindtextdomain($;$) {
|
||||
local ($_, %_);
|
||||
my ($domain, $LOCALEDIR);
|
||||
($domain, $LOCALEDIR) = @_;
|
||||
# Return the current registry
|
||||
return (exists $LOCALEDIRS{$domain}? $LOCALEDIRS{$domain}: undef)
|
||||
if !defined $LOCALEDIR;
|
||||
# Register the locale directory
|
||||
$LOCALEDIRS{$domain} = $LOCALEDIR;
|
||||
# Reinitialize the text domain
|
||||
_init_textdomain($domain);
|
||||
# Reset the current language handle
|
||||
_get_handle() if defined $DOMAIN && $domain eq $DOMAIN;
|
||||
# Return the locale directory
|
||||
return $LOCALEDIR;
|
||||
}
|
||||
|
||||
# textdomain: Set the current text domain
|
||||
sub textdomain(;$) {
|
||||
local ($_, %_);
|
||||
my ($new_domain);
|
||||
$new_domain = $_[0];
|
||||
# Return the current text domain
|
||||
return $DOMAIN if !defined $new_domain;
|
||||
# Set the current text domain
|
||||
$DOMAIN = $new_domain;
|
||||
# Reinitialize the text domain
|
||||
_init_textdomain($DOMAIN);
|
||||
# Reset the current language handle
|
||||
_get_handle();
|
||||
return $DOMAIN;
|
||||
}
|
||||
|
||||
# get_handle: Get a language handle
|
||||
sub get_handle(@) {
|
||||
local ($_, %_);
|
||||
# Register the current get_handle arguments
|
||||
@LANGS = @_;
|
||||
# Reset and return the current language handle
|
||||
return _get_handle();
|
||||
}
|
||||
|
||||
# maketext: Maketext, in its long name
|
||||
# Use @ instead of $@ in prototype, so that we can pass @_ to it.
|
||||
sub maketext(@) {
|
||||
return __($_[0], @_[1..$#_]);
|
||||
}
|
||||
|
||||
# __: Maketext, in its shortcut name
|
||||
# Use @ instead of $@ in prototype, so that we can pass @_ to it.
|
||||
sub __(@) {
|
||||
local ($_, %_);
|
||||
my ($key, @param, $keyd);
|
||||
($key, @param) = @_;
|
||||
# Reset the current language handle if it is not set yet
|
||||
_get_handle() if !defined $LH;
|
||||
|
||||
# Decode the source text
|
||||
$keyd = $key;
|
||||
$keyd = decode($PARAMS{"KEY_ENCODING"}, $keyd, $PARAMS{"ENCODE_FAILURE"})
|
||||
if exists $PARAMS{"KEY_ENCODING"} && !Encode::is_utf8($key);
|
||||
# Maketext
|
||||
$_ = $LH->maketext($keyd, @param);
|
||||
# Output to the requested encoding
|
||||
if (exists $PARAMS{"ENCODING"}) {
|
||||
$_ = encode($PARAMS{"ENCODING"}, $_, $PARAMS{"ENCODE_FAILURE"});
|
||||
# Pass through the empty/invalid lexicon
|
||||
} elsif ( scalar(keys %{$LH->{"Lexicon"}}) == 0
|
||||
&& exists $PARAMS{"KEY_ENCODING"}
|
||||
&& !Encode::is_utf8($key)) {
|
||||
$_ = encode($PARAMS{"KEY_ENCODING"}, $_, $PARAMS{"ENCODE_FAILURE"});
|
||||
}
|
||||
|
||||
return $_;
|
||||
}
|
||||
|
||||
# N_: Return the original text untouched, so that it can be catched
|
||||
# with xgettext
|
||||
# Use @ instead of $@ in prototype, so that we can pass @_ to it.
|
||||
sub N_(@) {
|
||||
# Watch out for this Perl magic! :p
|
||||
return $_[0] unless wantarray;
|
||||
return @_;
|
||||
}
|
||||
|
||||
# dmaketext: Maketext in another text domain temporarily,
|
||||
# an equivalent to dgettext().
|
||||
sub dmaketext($$@) {
|
||||
local ($_, %_);
|
||||
my ($domain, $key, @param, $lh0, $domain0, $text);
|
||||
($domain, $key, @param) = @_;
|
||||
# Preserve the current status
|
||||
($lh0, $domain0) = ($LH, $DOMAIN);
|
||||
# Reinitialize the text domain
|
||||
textdomain($domain);
|
||||
# Maketext
|
||||
$text = maketext($key, @param);
|
||||
# Return the current status
|
||||
($LH, $DOMAIN) = ($lh0, $domain0);
|
||||
# Return the "made text"
|
||||
return $text;
|
||||
}
|
||||
|
||||
# pmaketext: Maketext with context,
|
||||
# an equivalent to pgettext().
|
||||
sub pmaketext($$@) {
|
||||
local ($_, %_);
|
||||
my ($ctxt, $key, @param);
|
||||
($ctxt, $key, @param) = @_;
|
||||
# This is actually a wrapper to the maketext() function
|
||||
return maketext("$ctxt\x04$key", @param);
|
||||
}
|
||||
|
||||
# dpmaketext: Maketext with context in another text domain temporarily,
|
||||
# an equivalent to dpgettext().
|
||||
sub dpmaketext($$$@) {
|
||||
local ($_, %_);
|
||||
my ($domain, $ctxt, $key, @param);
|
||||
($domain, $ctxt, $key, @param) = @_;
|
||||
# This is actually a wrapper to the dmaketext() function
|
||||
return dmaketext($domain, "$ctxt\x04$key", @param);
|
||||
}
|
||||
|
||||
# reload_text: Purge the lexicon cache
|
||||
sub reload_text() {
|
||||
# reload_text is static.
|
||||
Locale::Maketext::Gettext->reload_text;
|
||||
}
|
||||
|
||||
# encoding: Set the output encoding
|
||||
sub encoding(;$) {
|
||||
local ($_, %_);
|
||||
$_ = $_[0];
|
||||
|
||||
# Set the output encoding
|
||||
if (@_ > 0) {
|
||||
if (defined $_) {
|
||||
$PARAMS{"ENCODING"} = $_;
|
||||
} else {
|
||||
delete $PARAMS{"ENCODING"};
|
||||
}
|
||||
$PARAMS{"USERSET_ENCODING"} = $_;
|
||||
}
|
||||
|
||||
# Return the encoding
|
||||
return exists $PARAMS{"ENCODING"}? $PARAMS{"ENCODING"}: undef;
|
||||
}
|
||||
|
||||
# key_encoding: Set the encoding of the original text
|
||||
sub key_encoding(;$) {
|
||||
local ($_, %_);
|
||||
$_ = $_[0];
|
||||
|
||||
# Set the encoding used in the keys
|
||||
if (@_ > 0) {
|
||||
if (defined $_) {
|
||||
$PARAMS{"KEY_ENCODING"} = $_;
|
||||
} else {
|
||||
delete $PARAMS{"KEY_ENCODING"};
|
||||
}
|
||||
}
|
||||
|
||||
# Return the encoding
|
||||
return exists $PARAMS{"KEY_ENCODING"}? $PARAMS{"KEY_ENCODING"}: undef;
|
||||
}
|
||||
|
||||
# encode_failure: What to do if the text is out of your output encoding
|
||||
# Refer to Encode on possible values of this check
|
||||
sub encode_failure(;$) {
|
||||
local ($_, %_);
|
||||
$_ = $_[0];
|
||||
# Set and return the current setting
|
||||
$PARAMS{"ENCODE_FAILURE"} = $_ if @_ > 0;
|
||||
# Return the current setting
|
||||
return $PARAMS{"ENCODE_FAILURE"};
|
||||
}
|
||||
|
||||
# die_for_lookup_failures: Whether we should die for lookup failure
|
||||
# The default is no. GNU gettext never fails.
|
||||
sub die_for_lookup_failures(;$) {
|
||||
local ($_, %_);
|
||||
$_ = $_[0];
|
||||
# Set the current setting
|
||||
if (@_ > 0) {
|
||||
$PARAMS{"DIE_FOR_LOOKUP_FAILURES"} = $_? 1: 0;
|
||||
$LH->die_for_lookup_failures($PARAMS{"DIE_FOR_LOOKUP_FAILURES"});
|
||||
}
|
||||
# Return the current setting
|
||||
# Resetting the current language handle is not required
|
||||
# Lookup failures are handled by the fail handler directly
|
||||
return $PARAMS{"DIE_FOR_LOOKUP_FAILURES"};
|
||||
}
|
||||
|
||||
# _declare_class: Declare a class
|
||||
sub _declare_class($) {
|
||||
local ($_, %_);
|
||||
$_ = $_[0];
|
||||
eval << "EOT";
|
||||
package $_[0];
|
||||
use base qw(Locale::Maketext::Gettext);
|
||||
use vars qw(\@ISA %Lexicon);
|
||||
EOT
|
||||
}
|
||||
|
||||
# _catclass: Catenate the class name
|
||||
sub _catclass(@) {
|
||||
return join("::", @_);;
|
||||
}
|
||||
|
||||
# _init_textdomain: Initialize a text domain
|
||||
sub _init_textdomain($) {
|
||||
local ($_, %_);
|
||||
my ($domain, $k, @langs, $langs);
|
||||
$domain = $_[0];
|
||||
|
||||
# Return if text domain not specified yet
|
||||
return if !defined $domain;
|
||||
|
||||
# Obtain the available locales
|
||||
# A binded domain
|
||||
if (exists $LOCALEDIRS{$domain}) {
|
||||
@langs = _get_langs($LOCALEDIRS{$domain}, $domain);
|
||||
# Not binded
|
||||
} else {
|
||||
@langs = qw();
|
||||
# Search the system locale directories
|
||||
foreach (@SYSTEM_LOCALEDIRS) {
|
||||
@langs = _get_langs($_, $domain);
|
||||
# Domain not found in this directory
|
||||
next if @langs == 0;
|
||||
$LOCALEDIRS{$domain} = $_;
|
||||
last;
|
||||
}
|
||||
# Not found at last
|
||||
return if !exists $LOCALEDIRS{$domain};
|
||||
}
|
||||
$langs = join ",", sort @langs;
|
||||
|
||||
# Obtain the registry key
|
||||
$k = _k($domain);
|
||||
|
||||
# Available language list remains for this domain
|
||||
return if exists $LANGS{$k} && $LANGS{$k} eq $langs;
|
||||
# Register this new language list
|
||||
$LANGS{$k} = $langs;
|
||||
|
||||
my ($rid, $class);
|
||||
# Garbage collection - drop abandoned language handles
|
||||
if (exists $CLASSES{$k}) {
|
||||
delete $LHS{$_} foreach grep /^$CLASSES{$k}/, keys %LHS;
|
||||
}
|
||||
# Get a new class ID
|
||||
$rid = _new_rid();
|
||||
# Obtain the class name
|
||||
$class = _catclass($CLASSBASE, $rid);
|
||||
# Register the domain with this class
|
||||
$CLASSES{$k} = $class;
|
||||
# Declare this class
|
||||
_declare_class($class);
|
||||
# Declare its language subclasses
|
||||
_declare_class(_catclass($class, $_))
|
||||
foreach @langs;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# _get_langs: Search a locale directory and return the available languages
|
||||
sub _get_langs($$) {
|
||||
local ($_, %_);
|
||||
my ($dir, $domain, $DH, $entry, $MOfile);
|
||||
($dir, $domain) = @_;
|
||||
|
||||
@_ = qw();
|
||||
{
|
||||
opendir $DH, $dir or last;
|
||||
while (defined($entry = readdir $DH)) {
|
||||
# Skip hidden entries
|
||||
next if $entry =~ /^\./;
|
||||
# Skip non-directories
|
||||
next unless -d catdir($dir, $entry);
|
||||
# Skip locales with dot "." (trailing encoding)
|
||||
next if $entry =~ /\./;
|
||||
# Get the MO file name
|
||||
$MOfile = catfile($dir, $entry, $CATEGORY, "$domain.mo");
|
||||
# Skip if MO file is not available for this locale
|
||||
next if ! -f $MOfile && ! -r $MOfile;
|
||||
# Map C to i_default
|
||||
$entry = "i_default" if $entry eq "C";
|
||||
# Add this language
|
||||
push @_, lc $entry;
|
||||
}
|
||||
close $DH or last;
|
||||
}
|
||||
return @_;
|
||||
}
|
||||
|
||||
# _get_handle: Set the language handle with the current DOMAIN and @LANGS
|
||||
sub _get_handle() {
|
||||
local ($_, %_);
|
||||
my ($k, $class, $subclass);
|
||||
|
||||
# Lexicon empty if text domain not specified, or not binded yet
|
||||
return _get_empty_handle if !defined $DOMAIN || !exists $LOCALEDIRS{$DOMAIN};
|
||||
# Obtain the registry key
|
||||
$k = _k($DOMAIN);
|
||||
# Lexicon empty if text domain was not properly set yet
|
||||
return _get_empty_handle if !exists $CLASSES{$k};
|
||||
|
||||
# Get the localization class name
|
||||
$class = $CLASSES{$k};
|
||||
# Get the language handle
|
||||
$LH = $class->get_handle(@LANGS);
|
||||
# Lexicon empty if failed get_handle()
|
||||
return _get_empty_handle if !defined $LH;
|
||||
|
||||
# Obtain the subclass name of the got language handle
|
||||
$subclass = ref($LH);
|
||||
# Use the existing language handle whenever possible, to reduce
|
||||
# the initialization overhead
|
||||
if (exists $LHS{$subclass}) {
|
||||
$LH = $LHS{$subclass};
|
||||
if (!exists $PARAMS{"USERSET_ENCODING"}) {
|
||||
if (exists $LH->{"MO_ENCODING"}) {
|
||||
$PARAMS{"ENCODING"} = $LH->{"MO_ENCODING"};
|
||||
} else {
|
||||
delete $PARAMS{"ENCODING"};
|
||||
}
|
||||
}
|
||||
return _lang($LH)
|
||||
}
|
||||
|
||||
# Initialize it
|
||||
$LH->bindtextdomain($DOMAIN, $LOCALEDIRS{$DOMAIN});
|
||||
$LH->textdomain($DOMAIN);
|
||||
# Respect the MO file encoding unless there is a user preferrence
|
||||
if (!exists $PARAMS{"USERSET_ENCODING"}) {
|
||||
if (exists $LH->{"MO_ENCODING"}) {
|
||||
$PARAMS{"ENCODING"} = $LH->{"MO_ENCODING"};
|
||||
} else {
|
||||
delete $PARAMS{"ENCODING"};
|
||||
}
|
||||
}
|
||||
# We handle the encoding() and key_encoding() ourselves.
|
||||
$LH->key_encoding(undef);
|
||||
$LH->encoding(undef);
|
||||
# Register it
|
||||
$LHS{$subclass} = $LH;
|
||||
|
||||
return _lang($LH);
|
||||
}
|
||||
|
||||
# _get_empty_handle: Obtain the empty language handle
|
||||
sub _get_empty_handle() {
|
||||
local ($_, %_);
|
||||
if (!defined $_EMPTY) {
|
||||
$_EMPTY = Locale::Maketext::Gettext::Functions::_EMPTY->get_handle;
|
||||
$_EMPTY->key_encoding(undef);
|
||||
$_EMPTY->encoding(undef);
|
||||
}
|
||||
$LH = $_EMPTY;
|
||||
$LH->die_for_lookup_failures($PARAMS{"DIE_FOR_LOOKUP_FAILURES"});
|
||||
return _lang($LH);
|
||||
}
|
||||
|
||||
# _reset: Initialize everything
|
||||
sub _reset() {
|
||||
local ($_, %_);
|
||||
|
||||
%LOCALEDIRS = qw();
|
||||
undef $LH;
|
||||
undef $DOMAIN;
|
||||
@LANGS = qw();
|
||||
%PARAMS = qw();
|
||||
$PARAMS{"KEY_ENCODING"} = "US-ASCII";
|
||||
$PARAMS{"ENCODE_FAILURE"} = FB_DEFAULT;
|
||||
$PARAMS{"DIE_FOR_LOOKUP_FAILURES"} = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# _new_rid: Generate a new random ID
|
||||
sub _new_rid() {
|
||||
local ($_, %_);
|
||||
my ($id);
|
||||
|
||||
do {
|
||||
for ($id = "", $_ = 0; $_ < $RID_LEN; $_++) {
|
||||
$id .= $RID_CHARS[int rand scalar @RID_CHARS];
|
||||
}
|
||||
} while exists $RIDS{$id};
|
||||
$RIDS{$id} = 1;
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
# _k: Build the key for the domain registry
|
||||
sub _k($) {
|
||||
return join "\n", $LOCALEDIRS{$_[0]}, $CATEGORY, $_[0];
|
||||
}
|
||||
|
||||
# _lang: The langage from a language handle. language_tag is not quite sane.
|
||||
sub _lang($) {
|
||||
local ($_, %_);
|
||||
$_ = $_[0];
|
||||
$_ = ref($_);
|
||||
s/^.+:://;
|
||||
s/_/-/g;
|
||||
return $_;
|
||||
}
|
||||
|
||||
# Public empty lexicon
|
||||
package Locale::Maketext::Gettext::Functions::_EMPTY;
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use base qw(Locale::Maketext::Gettext);
|
||||
use vars qw($VERSION @ISA %Lexicon);
|
||||
$VERSION = 0.01;
|
||||
|
||||
package Locale::Maketext::Gettext::Functions::_EMPTY::i_default;
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use base qw(Locale::Maketext::Gettext);
|
||||
use vars qw($VERSION @ISA %Lexicon);
|
||||
$VERSION = 0.01;
|
||||
|
||||
return 1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Locale::Maketext::Gettext::Functions - Functional interface to Locale::Maketext::Gettext
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
bindtextdomain(DOMAIN, LOCALEDIR);
|
||||
textdomain(DOMAIN);
|
||||
get_handle("de");
|
||||
print __("Hello, world!\n");
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Locale::Maketext::Gettext::Functions is a functional
|
||||
interface to
|
||||
L<Locale::Maketext::Gettext(3)|Locale::Maketext::Gettext/3> (and
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3>). It works exactly the GNU
|
||||
gettext way. It plays magic to
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3> for you. No more
|
||||
localization class/subclasses and language handles are required at
|
||||
all.
|
||||
|
||||
The C<maketext>, C<dmaketext>, C<pmaketext> and C<dpmaketext>
|
||||
functions attempt to translate a text message into the native
|
||||
language of the user, by looking up the translation in an MO lexicon
|
||||
file.
|
||||
|
||||
=head1 FUNCTIONS
|
||||
|
||||
=over
|
||||
|
||||
=item bindtextdomain(DOMAIN, LOCALEDIR)
|
||||
|
||||
Register a text domain with a locale directory. Returns C<LOCALEDIR>
|
||||
itself. If C<LOCALEDIR> is omitted, the registered locale directory
|
||||
of C<DOMAIN> is returned. This method always success.
|
||||
|
||||
=item textdomain(DOMAIN)
|
||||
|
||||
Set the current text domain. Returns the C<DOMAIN> itself. if
|
||||
C<DOMAIN> is omitted, the current text domain is returned. This
|
||||
method always success.
|
||||
|
||||
=item get_handle(@languages)
|
||||
|
||||
Set the language of the user. It searches for an available language
|
||||
in the provided @languages list. If @languages was not provided, it
|
||||
looks checks environment variable LANG, and HTTP_ACCEPT_LANGUAGE
|
||||
when running as CGI. Refer to
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3> for the magic of the
|
||||
C<get_handle>.
|
||||
|
||||
=item $message = maketext($key, @param...)
|
||||
|
||||
Attempts to translate a text message into the native language of the
|
||||
user, by looking up the translation in an MO lexicon file. Refer to
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3> for the C<maketext> plural
|
||||
grammer.
|
||||
|
||||
=item $message = __($key, @param...)
|
||||
|
||||
A synonym to C<maketext()>. This is a shortcut to C<maketext()> so
|
||||
that it is cleaner when you employ maketext to your existing project.
|
||||
|
||||
=item ($key, @param...) = N_($key, @param...)
|
||||
|
||||
Returns the original text untouched. This is to enable the text be
|
||||
catched with xgettext.
|
||||
|
||||
=item $message = dmaketext($domain, $key, @param...)
|
||||
|
||||
Temporarily switch to another text domain and attempts to translate
|
||||
a text message into the native language of the user in that text
|
||||
domain. Use "--keyword=dmaketext:2" for the xgettext utility.
|
||||
|
||||
=item $message = pmaketext($ctxt, $key, @param...)
|
||||
|
||||
Attempts to translate a text message in a particular context into the
|
||||
native language of the user. Use "--keyword=pmaketext:1c,2" for
|
||||
the xgettext utility.
|
||||
|
||||
=item $message = dpmaketext($domain, $ctxt, $key, @param...)
|
||||
|
||||
Temporarily switch to another text domain and attempts to translate
|
||||
a text message in a particular context into the native language of
|
||||
the user in that text domain. Use "--keyword=dpmaketext:2c,3" for
|
||||
the xgettext utility.
|
||||
|
||||
=item encoding(ENCODING)
|
||||
|
||||
Set or retrieve the output encoding. The default is the same
|
||||
encoding as the gettext MO file. You can specify C<undef>, to return
|
||||
the result in unencoded UTF-8.
|
||||
|
||||
=item key_encoding(ENCODING)
|
||||
|
||||
Specify the encoding used in your original text. The C<maketext>
|
||||
method itself is not multibyte-safe to the _AUTO lexicon. If you are
|
||||
using your native non-English language as your original text and you
|
||||
are having troubles like:
|
||||
|
||||
Unterminated bracket group, in:
|
||||
|
||||
Then, specify the C<key_encoding> to the encoding of your original
|
||||
text. Returns the current setting.
|
||||
|
||||
B<WARNING:> You should always use US-ASCII text keys. Using
|
||||
non-US-ASCII keys is always discouraged and is not guaranteed to
|
||||
be working.
|
||||
|
||||
=item encode_failure(CHECK)
|
||||
|
||||
Set the action when encode fails. This happens when the output text
|
||||
is out of the scope of your output encoding. For exmaple, output
|
||||
Chinese into US-ASCII. Refer to L<Encode(3)|Encode/3> for the
|
||||
possible values of this C<CHECK>. The default is C<FB_DEFAULT>,
|
||||
which is a safe choice that never fails. But part of your text may
|
||||
be lost, since that is what C<FB_DEFAULT> does. Returns the current
|
||||
setting.
|
||||
|
||||
=item die_for_lookup_failures(SHOULD_I_DIE)
|
||||
|
||||
Maketext dies for lookup failures, but GNU gettext never fails.
|
||||
By default Lexicon::Maketext::Gettext follows the GNU gettext
|
||||
behavior. But if you are Maketext-styled, or if you need a better
|
||||
control over the failures (like me :p), set this to 1. Returns the
|
||||
current setting.
|
||||
|
||||
=item reload_text()
|
||||
|
||||
Purges the MO text cache. By default MO files are cached after they
|
||||
are read and parsed from the disk, to reduce I/O and parsing overhead
|
||||
on busy sites. reload_text() purges this cache, so that updated MO
|
||||
files can take effect at run-time. This is used when your MO file is
|
||||
updated, but you cannot shutdown and restart the application. for
|
||||
example, when you are a co-hoster on a mod_perl-enabled Apache, or
|
||||
when your mod_perl-enabled Apache is too vital to be restarted for
|
||||
every update of your MO file, or if you are running a vital daemon,
|
||||
such as an X display server.
|
||||
|
||||
=item %Lexicon = read_mo($MOfile)
|
||||
|
||||
Read and parse the MO file. Returns the read %Lexicon. The returned
|
||||
lexicon is in its original encoding.
|
||||
|
||||
If you need the meta infomation of your MO file, parse the entry
|
||||
C<$Lexicon{""}>. For example:
|
||||
|
||||
/^Content-Type: text\/plain; charset=(.*)$/im;
|
||||
$encoding = $1;
|
||||
|
||||
=back
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
B<NOTE:> Since localization classes are generated at run-time, it is
|
||||
not possible to override the Maketext language functions, like
|
||||
C<quant> or C<numerate>. If that is your concern, use
|
||||
L<Locale::Maketext::Gettext(3)|Locale::Maketext::Gettext/3> instead.
|
||||
Suggestions are welcome.
|
||||
|
||||
You can now add/remove languages/MO files at run-time. This is a
|
||||
major improvement over the original
|
||||
L<Locale::Maketext::Gettext(3)|Locale::Maketext::Gettext/3> (and
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3>). This is done by
|
||||
registering localization classes with random IDs, so that the same
|
||||
text domain can be re-declared infinitely, whenever needed (language
|
||||
list changes, LOCALEDIR changes, etc.) This is not possible to the
|
||||
object-interface of
|
||||
L<Locale::Maketext::Gettext(3)|Locale::Maketext::Gettext/3> (and
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3>).
|
||||
|
||||
Language addition/removal takes effect only after C<bindtextdomain>
|
||||
or C<textdomain> is called. It has no effect on C<maketext> calls.
|
||||
This keeps a basic sanity in the lifetime of a running script.
|
||||
|
||||
If you set C<textdomain> to a domain that is not C<bindtextdomain> to
|
||||
specific a locale directory yet, it will try search system locale
|
||||
directories. The current system locale directory search order is:
|
||||
/usr/share/locale, /usr/lib/locale, /usr/local/share/locale,
|
||||
/usr/local/lib/locale. Suggestions are welcome.
|
||||
|
||||
=head1 STORY
|
||||
|
||||
The idea is that: I finally realized that, no matter how hard I try,
|
||||
I<I can never get a never-failure C<maketext>.> A common wrapper
|
||||
like:
|
||||
|
||||
sub __ { return $LH->maketext(@_) };
|
||||
|
||||
always fails if $LH is not initialized yet. For this reason,
|
||||
C<maketext> can hardly be employed in error handlers to output
|
||||
graceful error messages in the natural language of the user. So,
|
||||
I have to write something like this:
|
||||
|
||||
sub __ {
|
||||
$LH = MyPkg::L10N->get_handle if !defined $LH;
|
||||
return $LH->maketext(@_);
|
||||
}
|
||||
|
||||
But what if C<get_handle> itself fails? So, this becomes:
|
||||
|
||||
sub __ {
|
||||
$LH = MyPkg::L10N->get_handle if !defined $LH;
|
||||
$LH = _AUTO->get_handle if !defined $LH;
|
||||
return $LH->maketext(@_);
|
||||
}
|
||||
package _AUTO;
|
||||
use base qw(Locale::Maketext);
|
||||
package _AUTO::i_default;
|
||||
use base qw(Locale::Maketext);
|
||||
%Lexicon = ( "_AUTO" => 1 );
|
||||
|
||||
Ya, this works. But, if I always have to do this in my every
|
||||
application, why should I not make a solution to the localization
|
||||
framework itself? This is a common problem to every localization
|
||||
projects. It should be solved at the localization framework level,
|
||||
but not at the application level.
|
||||
|
||||
Another reason is that: I<Programmers should be able to use
|
||||
C<maketext> without the knowledge of object-oriented programming.>
|
||||
A localization framework should be neat and simple. It should lower
|
||||
down its barrier, be friendly to the beginners, in order to
|
||||
encourage the use of localization and globalization. Apparently
|
||||
the current practice of L<Locale::Maketext(3)|Locale::Maketext/3>
|
||||
does not satisfy this request.
|
||||
|
||||
The third reason is: Since
|
||||
L<Locale::Maketext::Gettext(3)|Locale::Maketext::Gettext/3> imports
|
||||
the lexicon from foreign sources, the class source file is left
|
||||
empty. It exists only to help the C<get_handle> method looking for
|
||||
a proper language handle. Then, why not make it disappear, and be
|
||||
generated whenever needed? Why bother the programmers to put
|
||||
an empty class source file there?
|
||||
|
||||
How neat can we be?
|
||||
|
||||
imacat, 2003-04-29
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
Since maketext localization classes are generated at run time,
|
||||
Maketext language function override, like C<quant> or C<numerate>, is
|
||||
not available here. Suggestions are welcome.
|
||||
|
||||
C<encoding>, C<key_encoding>, C<encode_failure> and
|
||||
C<die_for_lookup_failures> are not mod_perl-safe. These settings
|
||||
affect the whole process, including the following scripts it is
|
||||
going to run. This is the same as C<setlocale> in
|
||||
L<POSIX(3)|POSIX/3>. Always set them at the very beginning of your
|
||||
script if you are running under mod_perl. If you do not like it,
|
||||
use the object-oriented
|
||||
L<Locale::Maketext::Gettext(3)|Locale::Maketext::Gettext/3> instead.
|
||||
Suggestions are welcome.
|
||||
|
||||
Smart translation between Traditional Chinese/Simplified Chinese,
|
||||
like what GNU gettext does, is not available yet. Suggestions are
|
||||
welcome.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3>,
|
||||
L<Locale::Maketext::TPJ13(3)|Locale::Maketext::TPJ13/3>,
|
||||
L<Locale::Maketext::Gettext(3)|Locale::Maketext::Gettext/3>,
|
||||
L<bindtextdomain(3)|bindtextdomain/3>, L<textdomain(3)|textdomain/3>.
|
||||
Also, please refer to the official GNU gettext manual at
|
||||
L<http://www.gnu.org/software/gettext/manual/>.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
imacat <imacat@mail.imacat.idv.tw>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (c) 2003-2008 imacat. All rights reserved. This program is free
|
||||
software; you can redistribute it and/or modify it under the same terms
|
||||
as Perl itself.
|
||||
|
||||
=cut
|
215
script/maketext
Executable file
215
script/maketext
Executable file
@ -0,0 +1,215 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Command-line interface to Locale::Maketext::Gettext (and Locale::Maketext)
|
||||
|
||||
# Copyright (c) 2003-2007 imacat. All rights reserved. This program is free
|
||||
# software; you can redistribute it and/or modify it under the same terms
|
||||
# as Perl itself.
|
||||
# First written: 2003-05-03
|
||||
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Getopt::Long qw(GetOptions);
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
use vars qw($VERSION);
|
||||
$VERSION = 0.05;
|
||||
# Prototype declaration
|
||||
sub main();
|
||||
sub parse_args();
|
||||
|
||||
use vars qw($THIS_FILE $SHORTHELP $VERSTR $SEARCH $HELP);
|
||||
$THIS_FILE = $0;
|
||||
$THIS_FILE =~ s/^.*\///;
|
||||
$SHORTHELP = "Try `$THIS_FILE --help' for more information.";
|
||||
$VERSTR = "$THIS_FILE v$VERSION by imacat <imacat\@mail.imacat.idv.tw>";
|
||||
$SEARCH = join " ", @Locale::Maketext::Gettext::Functions::SYSTEM_LOCALEDIRS;
|
||||
$HELP = << "EOT";
|
||||
Usage: maketext [OPTION] [--domain=TEXTDOMAIN] MSGKEY [PARAM...]
|
||||
or: maketext [OPTION] -s MSGID [PARAM...]
|
||||
|
||||
Maketext and display native language translation of a textual message.
|
||||
|
||||
-d, --domain=TEXTDOMAIN retrieve translated messages from TEXTDOMAIN
|
||||
-h, --help display this help and exit
|
||||
-V, --version display version information and exit
|
||||
MSGKEY [PARAM...] retrieve translated message corresponding
|
||||
to MSGKEY from TEXTDOMAIN
|
||||
|
||||
If the TEXTDOMAIN parameter is not given, the domain is determined from the
|
||||
environment variable TEXTDOMAIN. If the message catalog is not found in the
|
||||
regular directory, another location can be specified with the environment
|
||||
variable TEXTDOMAINDIR.
|
||||
When used with the -s option the program adds a new line to the end of the
|
||||
output so that it behaves like the `echo' or the `gettext' command.
|
||||
Standard search directories: $SEARCH
|
||||
|
||||
Report bugs to <imacat\@mail.imacat.idv.tw>.
|
||||
EOT
|
||||
|
||||
use vars qw($DOMAIN $LOCALEDIR $ECHO $KEY @PARAM);
|
||||
$ECHO = 0;
|
||||
|
||||
# Main program
|
||||
main();
|
||||
exit 0;
|
||||
|
||||
# main: Main program
|
||||
sub main() {
|
||||
local ($_, %_);
|
||||
|
||||
# Parse the arguments
|
||||
parse_args();
|
||||
|
||||
bindtextdomain($DOMAIN, $LOCALEDIR)
|
||||
if defined $DOMAIN && defined $LOCALEDIR;
|
||||
textdomain($DOMAIN) if defined $DOMAIN;
|
||||
print maketext($KEY, @PARAM);
|
||||
print "\n" if $ECHO;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# parse_args: Parse the arguments
|
||||
sub parse_args() {
|
||||
local ($_, %_);
|
||||
|
||||
# Get the arguments ¨ú±o°Ñ¼Æ
|
||||
$_ = eval {
|
||||
local $SIG{__WARN__} = sub { die $_[0]; };
|
||||
Getopt::Long::Configure("no_auto_abbrev");
|
||||
GetOptions( "domain|d=s"=>\$DOMAIN,
|
||||
"s"=>sub { $ECHO = 1; },
|
||||
"help|h"=>sub { print $HELP; exit 0; },
|
||||
"version|V"=>sub { print "$VERSTR\n"; exit 0; });
|
||||
return 1;
|
||||
};
|
||||
die "$THIS_FILE: $@" if !defined $_;
|
||||
|
||||
# The MSGKEY
|
||||
die "$THIS_FILE: missing arguments\n" if @ARGV == 0;
|
||||
$KEY = shift @ARGV;
|
||||
@PARAM = @ARGV;
|
||||
|
||||
# Set the locale directory
|
||||
$LOCALEDIR = $ENV{"TEXTDOMAINDIR"} if exists $ENV{"TEXTDOMAINDIR"};
|
||||
# Set the text domain
|
||||
$DOMAIN = $ENV{"TEXTDOMAIN"}
|
||||
if !defined $DOMAIN && exists $ENV{"TEXTDOMAIN"};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
maketext - translate and make messages
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
maketext [OPTION] [--domain=TEXTDOMAIN] MSGKEY [PARAM...]
|
||||
maketext [OPTION] -s MSGID [PARAM...]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The C<maketext> script translates a natural language message into
|
||||
the user's language, by looking up the translation in a message MO
|
||||
file, and process the plural transformation with Maketext.
|
||||
|
||||
The C<maketext> script is a command-line interface to
|
||||
L<Locale::Maketext::Gettext(3)|Locale::Maketext::Gettext/3> (and
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3>). It can be used in shell
|
||||
scripts, etc, to translate, maketext and return the result. By this
|
||||
way, it enables Maketext to be integrated into other programming
|
||||
languages/systems, like bash/csh, python, PHP, C, etc. It works
|
||||
like the command-line program gettext.
|
||||
|
||||
For example:
|
||||
|
||||
% maketext -s "[*,_1,virus was,viruses were] found in [*,_2,file,files]." 0 1
|
||||
0 viruses were found in 1 file.
|
||||
% maketext -s "[*,_1,virus was,viruses were] found in [*,_2,file,files]." 1 3
|
||||
1 virus was found in 3 files.
|
||||
%
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over
|
||||
|
||||
=item -d,--domain=TEXTDOMAIN
|
||||
|
||||
Retrieve translated messages from TEXTDOMAIN.
|
||||
|
||||
=item -s
|
||||
|
||||
Adds a new line to the end of the output so that it behaves like the
|
||||
`echo' or the `gettext' command.
|
||||
|
||||
=item -h,--help
|
||||
|
||||
Display the help messages.
|
||||
|
||||
=item -V,--version
|
||||
|
||||
Display version information and exit.
|
||||
|
||||
=item MSGKEY
|
||||
|
||||
The original text used to look up translated text.
|
||||
|
||||
=item PARAM...
|
||||
|
||||
Parameters to Maketext for the plural and other text functions.
|
||||
|
||||
=back
|
||||
|
||||
=head1 ENVIRONMENT
|
||||
|
||||
=over
|
||||
|
||||
=item TEXTDOMAIN
|
||||
|
||||
TEXTDOMAIN is used to determine the text domain when the -d
|
||||
parameter is not given.
|
||||
|
||||
=item TEXTDOMAINDIR
|
||||
|
||||
TEXTDOMAINDIR is used to search the message catelog/MO file if it
|
||||
does not reside in the system locale directories.
|
||||
|
||||
=back
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
Maketext language function override, like C<quant> or C<numerate>, is
|
||||
not available here. Suggestions are welcome.
|
||||
|
||||
The current system locale directory search order is:
|
||||
/usr/share/locale, /usr/lib/locale, /usr/local/share/locale,
|
||||
/usr/local/lib/locale. Suggestions are welcome.
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
Report bugs to imacat <imacat@mail.imacat.idv.tw>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Locale::Maketext(3)|Locale::Maketext/3>,
|
||||
L<Locale::Maketext::TPJ13(3)|Locale::Maketext::TPJ13/3>,
|
||||
L<Locale::Maketext::Gettext(3)|Locale::Maketext::Gettext/3>,
|
||||
L<Locale::Maketext::Gettext::Functions(3)|Locale::Maketext::Gettext::Functions/3>,
|
||||
L<bindtextdomain(3)|bindtextdomain/3>, L<textdomain(3)|textdomain/3>.
|
||||
Also, please refer to the official GNU gettext manual at
|
||||
L<http://www.gnu.org/software/gettext/manual/>.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
imacat <imacat@mail.imacat.idv.tw>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (c) 2003-2007 imacat. All rights reserved. This program is free
|
||||
software; you can redistribute it and/or modify it under the same terms
|
||||
as Perl itself.
|
||||
|
||||
=cut
|
22
t/00-signature.t
Executable file
22
t/00-signature.t
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/perl
|
||||
use strict;
|
||||
print "1..1\n";
|
||||
|
||||
if (!-s 'SIGNATURE') {
|
||||
print "ok 1 # skip No signature file found\n";
|
||||
}
|
||||
elsif (!eval { require Module::Signature; 1 }) {
|
||||
print "ok 1 # skip ",
|
||||
"Next time around, consider install Module::Signature, ",
|
||||
"so you can verify the integrity of this distribution.\n";
|
||||
}
|
||||
elsif (!eval { require Socket; Socket::inet_aton('pgp.mit.edu') }) {
|
||||
print "ok 1 # skip Cannot connect to the keyserver\n";
|
||||
}
|
||||
else {
|
||||
(Module::Signature::verify() == Module::Signature::SIGNATURE_OK())
|
||||
or print "not ";
|
||||
print "ok 1 # Valid signature\n";
|
||||
}
|
||||
|
||||
__END__
|
150
t/01-basic.t
Executable file
150
t/01-basic.t
Executable file
@ -0,0 +1,150 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Basic test suite
|
||||
# Copyright (c) 2003-2008 imacat. All rights reserved. This program is free
|
||||
# software; you can redistribute it and/or modify it under the same terms
|
||||
# as Perl itself.
|
||||
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test;
|
||||
|
||||
BEGIN { plan tests => 22 }
|
||||
|
||||
use FindBin;
|
||||
use File::Spec::Functions qw(catdir catfile);
|
||||
use lib $FindBin::Bin;
|
||||
use vars qw($LOCALEDIR $r);
|
||||
$LOCALEDIR = catdir($FindBin::Bin, "locale");
|
||||
|
||||
# Basic test suite
|
||||
use Encode qw(decode);
|
||||
use vars qw($META $n $k1 $k2 $s1 $s2);
|
||||
|
||||
# bindtextdomain
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_ = $_->bindtextdomain("test");
|
||||
return 1;
|
||||
};
|
||||
# 1
|
||||
ok($r, 1);
|
||||
# 2
|
||||
ok($_, "$LOCALEDIR");
|
||||
|
||||
# textdomain
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_ = $_->textdomain;
|
||||
return 1;
|
||||
};
|
||||
# 3
|
||||
ok($r, 1);
|
||||
# 4
|
||||
ok($_, "test");
|
||||
|
||||
# read_mo
|
||||
$META = << "EOT";
|
||||
Project-Id-Version: test 1.1
|
||||
Report-Msgid-Bugs-To:
|
||||
POT-Creation-Date: 2008-02-19 12:31+0800
|
||||
PO-Revision-Date: 2008-02-19 12:31+0800
|
||||
Last-Translator: imacat <imacat\@mail.imacat.idv.tw>
|
||||
Language-Team: English <imacat\@mail.imacat.idv.tw>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=US-ASCII
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Plural-Forms: nplurals=2; plural=n != 1;
|
||||
EOT
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext;
|
||||
$_ = catfile($LOCALEDIR, "en", "LC_MESSAGES", "test.mo");
|
||||
%_ = read_mo($_);
|
||||
@_ = sort keys %_;
|
||||
$n = scalar(@_);
|
||||
$k1 = $_[0];
|
||||
$k2 = $_[1];
|
||||
$s1 = $_{$k1};
|
||||
$s2 = $_{$k2};
|
||||
return 1;
|
||||
};
|
||||
# 5
|
||||
ok($r, 1);
|
||||
# 6
|
||||
ok($n, 4);
|
||||
# 7
|
||||
ok($k1, "");
|
||||
# 8
|
||||
ok($k2, "Hello, world!");
|
||||
# 9
|
||||
ok($s1, $META);
|
||||
# 10
|
||||
ok($s2, "Hiya :)");
|
||||
|
||||
# English
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
@_ = qw();
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_[0] = $_->maketext("Hello, world!");
|
||||
$_[1] = $_->pmaketext("Menu|File|", "Hello, world!");
|
||||
$_[2] = $_->pmaketext("Menu|View|", "Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 11
|
||||
ok($r, 1);
|
||||
# 12
|
||||
ok($_[0], "Hiya :)");
|
||||
# 13
|
||||
ok($_[1], "Hiya :) under the File menu");
|
||||
# 14
|
||||
ok($_[2], "Hiya :) under the View menu");
|
||||
|
||||
# Traditional Chinese
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
@_ = qw();
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_[0] = $_->maketext("Hello, world!");
|
||||
$_[1] = $_->pmaketext("Menu|File|", "Hello, world!");
|
||||
$_[2] = $_->pmaketext("Menu|View|", "Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 15
|
||||
ok($r, 1);
|
||||
# 16
|
||||
ok($_[0], "<22>產<EFBFBD><E794A2>");
|
||||
# 17
|
||||
ok($_[1], "郎<>匡虫<E58CA1><E899AB><EFBFBD>產<EFBFBD><E794A2>");
|
||||
# 18
|
||||
ok($_[2], "聅凝匡虫<E58CA1><E899AB><EFBFBD>產<EFBFBD><E794A2>");
|
||||
|
||||
# Simplified Chinese
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
@_ = qw();
|
||||
$_ = T_L10N->get_handle("zh-cn");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_[0] = $_->maketext("Hello, world!");
|
||||
$_[1] = $_->pmaketext("Menu|File|", "Hello, world!");
|
||||
$_[2] = $_->pmaketext("Menu|View|", "Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 19
|
||||
ok($r, 1);
|
||||
# 20
|
||||
ok($_[0], "大家好。");
|
||||
# 21
|
||||
ok($_[1], "档案菜单下的大家好。");
|
||||
# 22
|
||||
ok($_[2], "浏览菜单下的大家好。");
|
143
t/02-big-endian.t
Executable file
143
t/02-big-endian.t
Executable file
@ -0,0 +1,143 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Test the big endian MO files
|
||||
# Copyright (c) 2003-2009 imacat. All rights reserved. This program is free
|
||||
# software; you can redistribute it and/or modify it under the same terms
|
||||
# as Perl itself.
|
||||
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test;
|
||||
|
||||
BEGIN { plan tests => 10 }
|
||||
|
||||
use FindBin;
|
||||
use File::Spec::Functions qw(catdir catfile);
|
||||
use lib $FindBin::Bin;
|
||||
use vars qw($LOCALEDIR $r);
|
||||
$LOCALEDIR = catdir($FindBin::Bin, "locale");
|
||||
|
||||
# Check reading big-endian PO files
|
||||
use vars qw($skip $POfile $MOfile $hasctxt);
|
||||
# English
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->bindtextdomain("test_be", $LOCALEDIR);
|
||||
$_->textdomain("test_be");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 1
|
||||
ok($r, 1);
|
||||
# 2
|
||||
ok($_, "Hiya :)");
|
||||
|
||||
# Traditional Chinese
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test_be", $LOCALEDIR);
|
||||
$_->textdomain("test_be");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 3
|
||||
ok($r, 1);
|
||||
# 4
|
||||
ok($_, "¤j®a¦n¡C");
|
||||
|
||||
# Simplified Chinese
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-cn");
|
||||
$_->bindtextdomain("test_be", $LOCALEDIR);
|
||||
$_->textdomain("test_be");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 5
|
||||
ok($r, 1);
|
||||
# 6
|
||||
ok($_, "´ó¼ÒºÃ¡£");
|
||||
|
||||
# Native-built MO file
|
||||
{
|
||||
my $FH;
|
||||
$skip = 1;
|
||||
$POfile = catfile($FindBin::Bin, "test_native.po");
|
||||
$MOfile = catfile($LOCALEDIR, "en", "LC_MESSAGES", "test_native.mo");
|
||||
$_ = join "", `msgfmt --version 2>&1`;
|
||||
last unless $? == 0;
|
||||
last unless /GNU gettext/;
|
||||
last unless /GNU gettext.* (\d+)\.(\d+)/;
|
||||
# Gettext from 0.15 has msgctxt
|
||||
$hasctxt = $1 > 0 || ($1 == 0 && $2 >= 15);
|
||||
$_ = << "EOT";
|
||||
# English PO file for the test_native project.
|
||||
# Copyright (C) 2003-2009 imacat
|
||||
# This file is distributed under the same license as the commonlib package.
|
||||
# imacat <imacat\@mail.imacat.idv.tw>, 2003-%1\$04d.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: test_native 1.1\\n"
|
||||
"Report-Msgid-Bugs-To: \\n"
|
||||
"POT-Creation-Date: %1\$04d-%2\$02d-%3\$02d %4\$02d:%5\$02d+0800\\n"
|
||||
"PO-Revision-Date: %1\$04d-%2\$02d-%3\$02d %4\$02d:%5\$02d+0800\\n"
|
||||
"Last-Translator: imacat <imacat\@mail.imacat.idv.tw>\\n"
|
||||
"Language-Team: English <imacat\@mail.imacat.idv.tw>\\n"
|
||||
"MIME-Version: 1.0\\n"
|
||||
"Content-Type: text/plain; charset=US-ASCII\\n"
|
||||
"Content-Transfer-Encoding: 7bit\\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\\n"
|
||||
|
||||
#: test_native.pl:100
|
||||
msgid "Hello, world!"
|
||||
msgstr "Hiya :)"
|
||||
EOT
|
||||
$_ .= << "EOT" if $hasctxt;
|
||||
|
||||
#: test_native.pl:103
|
||||
msgctxt "Menu|File|"
|
||||
msgid "Hello, world!"
|
||||
msgstr "Hiya :) under the File menu"
|
||||
|
||||
#: test_native.pl:106
|
||||
msgctxt "Menu|View|"
|
||||
msgid "Hello, world!"
|
||||
msgstr "Hiya :) under the View menu"
|
||||
EOT
|
||||
@_ = localtime;
|
||||
$_[5] += 1900;
|
||||
$_[4]++;
|
||||
$_ = sprintf $_, @_[5,4,3,2,1,0];
|
||||
open $FH, ">$POfile";
|
||||
print $FH $_;
|
||||
close $FH;
|
||||
`msgfmt -o "$MOfile" "$POfile"`;
|
||||
last unless $? == 0;
|
||||
$skip = 0;
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->bindtextdomain("test_native", $LOCALEDIR);
|
||||
$_->textdomain("test_native");
|
||||
$_[0] = $_->maketext("Hello, world!");
|
||||
$_[1] = $_->pmaketext("Menu|File|", "Hello, world!") if $hasctxt;
|
||||
$_[2] = $_->pmaketext("Menu|View|", "Hello, world!") if $hasctxt;
|
||||
return 1;
|
||||
};
|
||||
}
|
||||
# 7
|
||||
skip($skip, $r, 1);
|
||||
# 8
|
||||
skip($skip, $_[0], "Hiya :)");
|
||||
# 9
|
||||
skip($skip || !$hasctxt, $_[1], "Hiya :) under the File menu");
|
||||
# 10
|
||||
skip($skip || !$hasctxt, $_[2], "Hiya :) under the View menu");
|
||||
|
||||
# Garbage collection
|
||||
unlink $POfile;
|
||||
unlink $MOfile;
|
283
t/03-errors.t
Executable file
283
t/03-errors.t
Executable file
@ -0,0 +1,283 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Test suite for the behavior when something goes wrong
|
||||
# Copyright (c) 2003-2009 imacat. All rights reserved. This program is free
|
||||
# software; you can redistribute it and/or modify it under the same terms
|
||||
# as Perl itself.
|
||||
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test;
|
||||
|
||||
BEGIN { plan tests => 29 }
|
||||
|
||||
use Encode qw();
|
||||
use FindBin;
|
||||
use File::Basename qw(basename);
|
||||
use File::Spec::Functions qw(catdir catfile);
|
||||
use lib $FindBin::Bin;
|
||||
use vars qw($THIS_FILE $LOCALEDIR $r);
|
||||
$THIS_FILE = basename($0);
|
||||
$LOCALEDIR = catdir($FindBin::Bin, "locale");
|
||||
sub find_system_mo();
|
||||
|
||||
# find_system_mo: Find a safe system MO to be tested
|
||||
sub find_system_mo() {
|
||||
local ($_, %_);
|
||||
my %cands;
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
# Find all the system MO files
|
||||
%cands = qw();
|
||||
foreach my $dir (@Locale::Maketext::Gettext::Functions::SYSTEM_LOCALEDIRS) {
|
||||
my ($DH, @locales);
|
||||
next unless -d $dir;
|
||||
|
||||
@locales = qw();
|
||||
opendir $DH, $dir or die "$THIS_FILE: $dir: $!";
|
||||
while (defined($_ = readdir $DH)) {
|
||||
my $dir1;
|
||||
$dir1 = catfile($dir, $_, "LC_MESSAGES");
|
||||
push @locales, $_ if -d $dir1 && -r $dir1
|
||||
&& /^(?:en|zh_tw|zh_cn)$/i;
|
||||
}
|
||||
closedir $DH or die "$THIS_FILE: $dir: $!";
|
||||
|
||||
foreach my $loc (sort @locales) {
|
||||
my $dir1;
|
||||
$dir1 = catfile($dir, $loc, "LC_MESSAGES");
|
||||
opendir $DH, $dir1 or die "$THIS_FILE: $dir1: $!";
|
||||
while (defined($_ = readdir $DH)) {
|
||||
my ($file, $domain);
|
||||
$file = catfile($dir1, $_);
|
||||
next unless -f $file && -r $file && /^(.+)\.mo$/;
|
||||
$domain = $1;
|
||||
$cands{$file} = [$loc, $domain];
|
||||
}
|
||||
closedir $DH or die "$THIS_FILE: $dir1: $!";
|
||||
}
|
||||
}
|
||||
# Check each MO file, from the newest
|
||||
foreach my $file (sort { (stat $b)[9] <=> (stat $a)[9] } keys %cands) {
|
||||
my ($FH, $size, $content, $charset, $lang, $domain);
|
||||
$size = (stat $file)[7];
|
||||
open $FH, $file or die "$THIS_FILE: $file: $!";
|
||||
read $FH, $content, $size or die "$THIS_FILE: $file: $!";
|
||||
close $FH or die "$THIS_FILE: $file: $!";
|
||||
# Only take files whose meta information does not have special characters
|
||||
# that might be considered as code by Locale::Maketext
|
||||
next unless $content =~ /Project-Id-Version:([^\n\0\[\]~]+\n)+\0/;
|
||||
# Only take files that resolve to a valid character set
|
||||
next unless $content =~ /\s+charset=([^\n]+)/;
|
||||
$charset = $1;
|
||||
next unless defined Encode::resolve_alias($charset);
|
||||
# OK. We take this one
|
||||
($lang, $domain) = @{$cands{$file}};
|
||||
$lang = lc $lang;
|
||||
$lang =~ s/_/-/g;
|
||||
$lang = "i-default" if $lang eq "c";
|
||||
return ($lang, $domain);
|
||||
}
|
||||
# Not found
|
||||
return (undef, undef);
|
||||
}
|
||||
|
||||
# When something goes wrong
|
||||
use vars qw($dir $domain $lang $skip);
|
||||
# GNU gettext never fails!
|
||||
# bindtextdomain
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_ = $_->bindtextdomain("test");
|
||||
return 1;
|
||||
};
|
||||
# 1
|
||||
ok($r, 1);
|
||||
# 2
|
||||
ok($_, undef);
|
||||
|
||||
# textdomain
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_ = $_->textdomain;
|
||||
return 1;
|
||||
};
|
||||
# 3
|
||||
ok($r, 1);
|
||||
# 4
|
||||
ok($_, undef);
|
||||
|
||||
# No text domain claimed yet
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 5
|
||||
ok($r, 1);
|
||||
# 6
|
||||
ok($_, "Hello, world!");
|
||||
|
||||
# Non-existing LOCALEDIR
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->bindtextdomain("test", "/dev/null");
|
||||
$_->textdomain("test");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 7
|
||||
ok($r, 1);
|
||||
# 8
|
||||
ok($_, "Hello, world!");
|
||||
|
||||
# Not-registered DOMAIN
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->textdomain("not_registered");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 9
|
||||
ok($r, 1);
|
||||
# 10
|
||||
ok($_, "Hello, world!");
|
||||
|
||||
# PO file not exists
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->bindtextdomain("no_such_domain", $LOCALEDIR);
|
||||
$_->textdomain("no_such_domain");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 11
|
||||
ok($r, 1);
|
||||
# 12
|
||||
ok($_, "Hello, world!");
|
||||
|
||||
# PO file invalid
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->bindtextdomain("bad", $LOCALEDIR);
|
||||
$_->textdomain("bad");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 13
|
||||
ok($r, 1);
|
||||
# 14
|
||||
ok($_, "Hello, world!");
|
||||
|
||||
# No such message
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
@_ = qw();
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_[0] = $_->maketext("[*,_1,non-existing message,non-existing messages]", 1);
|
||||
$_[1] = $_->maketext("[*,_1,non-existing message,non-existing messages]", 3);
|
||||
$_[2] = $_->pmaketext("Menu|View|", "[*,_1,non-existing message,non-existing messages]", 1);
|
||||
$_[3] = $_->pmaketext("Menu|View|", "[*,_1,non-existing message,non-existing messages]", 3);
|
||||
$_[4] = $_->pmaketext("Menu|None|", "Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 15
|
||||
ok($r, 1);
|
||||
# 16
|
||||
ok($_[0], "1 non-existing message");
|
||||
# 17
|
||||
ok($_[1], "3 non-existing messages");
|
||||
# 18
|
||||
ok($_[2], "1 non-existing message");
|
||||
# 19
|
||||
ok($_[3], "3 non-existing messages");
|
||||
# 20
|
||||
ok($_[4], "Hello, world!");
|
||||
|
||||
# die_for_lookup_failures
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_->die_for_lookup_failures(1);
|
||||
$_ = $_->maketext("non-existing message");
|
||||
return 1;
|
||||
};
|
||||
# To be refined - to know that we failed at maketext()
|
||||
# was ok($@, qr/maketext doesn't know how to say/);
|
||||
# 21
|
||||
ok($r, undef);
|
||||
|
||||
# multibyte keys
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_->key_encoding("Big5");
|
||||
$_ = $_->maketext("¡]¥¼³]©w¡^");
|
||||
return 1;
|
||||
};
|
||||
# 22
|
||||
ok($r, 1);
|
||||
# 23
|
||||
ok($_, "¡]¥¼³]©w¡^");
|
||||
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test", "/dev/null");
|
||||
$_->textdomain("test");
|
||||
$_->key_encoding("Big5");
|
||||
$_ = $_->maketext("¡]¥¼³]©w¡^");
|
||||
return 1;
|
||||
};
|
||||
# 24
|
||||
ok($r, 1);
|
||||
# 25
|
||||
ok($_, "¡]¥¼³]©w¡^");
|
||||
|
||||
# Call maketext before and after binding text domain
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->maketext("Hello, world!");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 26
|
||||
ok($r, 1);
|
||||
# 27
|
||||
ok($_, "Hiya :)");
|
||||
|
||||
# Search system locale directories
|
||||
($lang, $domain) = find_system_mo;
|
||||
$skip = defined $domain? 0: 1;
|
||||
print "($lang, $domain)\n";
|
||||
$r = eval {
|
||||
return if $skip;
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle($lang);
|
||||
$_->textdomain($domain);
|
||||
print "OK 1111\n";
|
||||
$_ = $_->maketext("");
|
||||
# Skip if $Lexicon{""} does not exists
|
||||
$skip = 1 if $_ eq "";
|
||||
return 1;
|
||||
};
|
||||
# 28
|
||||
skip($skip, $r, 1);
|
||||
# 29
|
||||
skip($skip, $_, qr/Project-Id-Version:/);
|
266
t/04-encodings.t
Executable file
266
t/04-encodings.t
Executable file
@ -0,0 +1,266 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Test suite for different encodings
|
||||
# Copyright (c) 2003-2007 imacat. All rights reserved. This program is free
|
||||
# software; you can redistribute it and/or modify it under the same terms
|
||||
# as Perl itself.
|
||||
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test;
|
||||
|
||||
BEGIN { plan tests => 34 }
|
||||
|
||||
use Encode qw();
|
||||
use FindBin qw();
|
||||
use File::Spec::Functions qw(catdir);
|
||||
use lib $FindBin::Bin;
|
||||
use vars qw($LOCALEDIR $r);
|
||||
$LOCALEDIR = catdir($FindBin::Bin, "locale");
|
||||
|
||||
# Different encodings
|
||||
# English
|
||||
# Find the default encoding
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_ = $_->encoding;
|
||||
return 1;
|
||||
};
|
||||
# 1
|
||||
ok($r, 1);
|
||||
# 2
|
||||
ok($_, "US-ASCII");
|
||||
|
||||
# Traditional Chinese
|
||||
# Find the default encoding
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_ = $_->encoding;
|
||||
return 1;
|
||||
};
|
||||
# 3
|
||||
ok($r, 1);
|
||||
# 4
|
||||
ok($_, "Big5");
|
||||
|
||||
# Turn to Big5
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_->encoding("Big5");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 5
|
||||
ok($r, 1);
|
||||
# 6
|
||||
ok($_, "<22>產<EFBFBD><E794A2>");
|
||||
|
||||
# Turn to UTF-8
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_->encoding("UTF-8");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 7
|
||||
ok($r, 1);
|
||||
# 8
|
||||
ok($_, "澶у<E6BEB6>濂姐€<E5A790>");
|
||||
|
||||
# Turn to UTF-16LE
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_->encoding("UTF-16LE");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 9
|
||||
ok($r, 1);
|
||||
# 10
|
||||
ok($_, "'Y禰}Y0");
|
||||
|
||||
# Find the default encoding, in UTF-8
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test_utf8", $LOCALEDIR);
|
||||
$_->textdomain("test_utf8");
|
||||
$_ = $_->encoding;
|
||||
return 1;
|
||||
};
|
||||
# 11
|
||||
ok($r, 1);
|
||||
# 12
|
||||
ok($_, "UTF-8");
|
||||
|
||||
# Turn to UTF-8
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test_utf8", $LOCALEDIR);
|
||||
$_->textdomain("test_utf8");
|
||||
$_->encoding("UTF-8");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 13
|
||||
ok($r, 1);
|
||||
# 14
|
||||
ok($_, "澶у<E6BEB6>濂姐€<E5A790>");
|
||||
|
||||
# Turn to Big5
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test_utf8", $LOCALEDIR);
|
||||
$_->textdomain("test_utf8");
|
||||
$_->encoding("Big5");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 15
|
||||
ok($r, 1);
|
||||
# 16
|
||||
ok($_, "<22>產<EFBFBD><E794A2>");
|
||||
|
||||
# Turn to UTF-16LE
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test_utf8", $LOCALEDIR);
|
||||
$_->textdomain("test_utf8");
|
||||
$_->encoding("UTF-16LE");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 17
|
||||
ok($r, 1);
|
||||
# 18
|
||||
ok($_, "'Y禰}Y0");
|
||||
|
||||
# Find the default encoding
|
||||
# Simplified Chinese
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-cn");
|
||||
$_->bindtextdomain("test_utf8", $LOCALEDIR);
|
||||
$_->textdomain("test_utf8");
|
||||
$_ = $_->encoding;
|
||||
return 1;
|
||||
};
|
||||
# 19
|
||||
ok($r, 1);
|
||||
# 20
|
||||
ok($_, "UTF-8");
|
||||
|
||||
# Turn to GB2312
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-cn");
|
||||
$_->bindtextdomain("test_utf8", $LOCALEDIR);
|
||||
$_->textdomain("test_utf8");
|
||||
$_->encoding("GB2312");
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 21
|
||||
ok($r, 1);
|
||||
# 22
|
||||
ok($_, "大家好。");
|
||||
|
||||
# Encode failure
|
||||
# FB_DEFAULT
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test2", $LOCALEDIR);
|
||||
$_->textdomain("test2");
|
||||
$_->encoding("GB2312");
|
||||
$_ = $_->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 23
|
||||
ok($r, 1);
|
||||
# 24
|
||||
ok($_, "故事都有美?的?局。");
|
||||
|
||||
# FB_CROAK
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test2", $LOCALEDIR);
|
||||
$_->textdomain("test2");
|
||||
$_->encoding("GB2312");
|
||||
$_->encode_failure(Encode::FB_CROAK);
|
||||
$_ = $_->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 25
|
||||
ok($r, undef);
|
||||
# 26
|
||||
ok($@, qr/does not map to/);
|
||||
|
||||
# FB_HTMLCREF
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test2", $LOCALEDIR);
|
||||
$_->textdomain("test2");
|
||||
$_->encoding("GB2312");
|
||||
$_->encode_failure(Encode::FB_HTMLCREF);
|
||||
$_ = $_->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 27
|
||||
ok($r, 1);
|
||||
# 28
|
||||
ok($_, "故事都有美麗的結局。");
|
||||
|
||||
# Return the unencoded UTF-8 text
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_->encoding(undef);
|
||||
$_ = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 29
|
||||
ok($r, 1);
|
||||
# 30
|
||||
ok($_, "\x{5927}\x{5BB6}\x{597D}\x{3002}");
|
||||
# 31
|
||||
ok((Encode::is_utf8($_)? "utf8": "non-utf8"), "utf8");
|
||||
|
||||
# Return the unencoded UTF-8 text with auto lexicon
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_->encoding(undef);
|
||||
$_ = $_->maketext("Big watermelon");
|
||||
return 1;
|
||||
};
|
||||
# 32
|
||||
ok($r, 1);
|
||||
# 33
|
||||
ok($_, "Big watermelon");
|
||||
# 34
|
||||
ok((Encode::is_utf8($_)? "utf8": "non-utf8"), "utf8");
|
157
t/05-switching.t
Executable file
157
t/05-switching.t
Executable file
@ -0,0 +1,157 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Test suite for switching between different settings
|
||||
# Copyright (c) 2003-2008 imacat. All rights reserved. This program is free
|
||||
# software; you can redistribute it and/or modify it under the same terms
|
||||
# as Perl itself.
|
||||
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test;
|
||||
|
||||
BEGIN { plan tests => 25 }
|
||||
|
||||
use FindBin;
|
||||
use File::Spec::Functions qw(catdir catfile);
|
||||
use lib $FindBin::Bin;
|
||||
use vars qw($LOCALEDIR $r);
|
||||
$LOCALEDIR = catdir($FindBin::Bin, "locale");
|
||||
|
||||
# Switching between different settings
|
||||
use File::Copy qw(copy);
|
||||
use vars qw($lh1 $lh2 $dir $f $f1 $f2);
|
||||
|
||||
# 2 language handles of the same localization subclass
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
@_ = qw();
|
||||
$lh1 = T_L10N->get_handle("en");
|
||||
$lh1->bindtextdomain("test", $LOCALEDIR);
|
||||
$lh1->textdomain("test");
|
||||
$lh2 = T_L10N->get_handle("en");
|
||||
$lh2->bindtextdomain("test2", $LOCALEDIR);
|
||||
$lh2->textdomain("test2");
|
||||
$_[0] = $lh1->maketext("Hello, world!");
|
||||
$_[1] = $lh1->maketext("Every story has a happy ending.");
|
||||
$_[2] = $lh2->maketext("Hello, world!");
|
||||
$_[3] = $lh2->maketext("Every story has a happy ending.");
|
||||
$_[4] = $lh1->maketext("Hello, world!");
|
||||
$_[5] = $lh1->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 1
|
||||
ok($r, 1);
|
||||
# 2
|
||||
ok($_[0], "Hiya :)");
|
||||
# 3
|
||||
ok($_[1], "Every story has a happy ending.");
|
||||
# 4
|
||||
ok($_[2], "Hello, world!");
|
||||
# 5
|
||||
ok($_[3], "Pray it.");
|
||||
# 6
|
||||
ok($_[4], "Hiya :)");
|
||||
# 7
|
||||
ok($_[5], "Every story has a happy ending.");
|
||||
|
||||
# Switch between domains
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
@_ = qw();
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->bindtextdomain("test2", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_[0] = $_->maketext("Hello, world!");
|
||||
$_[1] = $_->maketext("Every story has a happy ending.");
|
||||
$_->textdomain("test2");
|
||||
$_[2] = $_->maketext("Hello, world!");
|
||||
$_[3] = $_->maketext("Every story has a happy ending.");
|
||||
$_->textdomain("test");
|
||||
$_[4] = $_->maketext("Hello, world!");
|
||||
$_[5] = $_->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 8
|
||||
ok($r, 1);
|
||||
# 9
|
||||
ok($_[0], "Hiya :)");
|
||||
# 10
|
||||
ok($_[1], "Every story has a happy ending.");
|
||||
# 11
|
||||
ok($_[2], "Hello, world!");
|
||||
# 12
|
||||
ok($_[3], "Pray it.");
|
||||
# 13
|
||||
ok($_[4], "Hiya :)");
|
||||
# 14
|
||||
ok($_[5], "Every story has a happy ending.");
|
||||
|
||||
# Switch between encodings
|
||||
$r = eval {
|
||||
require T_L10N;
|
||||
@_ = qw();
|
||||
$_ = T_L10N->get_handle("zh-tw");
|
||||
$_->bindtextdomain("test", $LOCALEDIR);
|
||||
$_->textdomain("test");
|
||||
$_->encoding("Big5");
|
||||
$_[0] = $_->maketext("Hello, world!");
|
||||
$_->encoding("UTF-8");
|
||||
$_[1] = $_->maketext("Hello, world!");
|
||||
$_->encoding("Big5");
|
||||
$_[2] = $_->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 15
|
||||
ok($r, 1);
|
||||
# 16
|
||||
ok($_[0], "大家好。");
|
||||
# 17
|
||||
ok($_[1], "憭批振憟賬<E6869F><E8B3AC>");
|
||||
# 18
|
||||
ok($_[2], "大家好。");
|
||||
|
||||
# Reload the text
|
||||
$r = eval {
|
||||
$dir = catdir($LOCALEDIR, "en", "LC_MESSAGES");
|
||||
$f = catfile($dir, "test_reload.mo");
|
||||
$f1 = catfile($dir, "test.mo");
|
||||
$f2 = catfile($dir, "test2.mo");
|
||||
unlink $f;
|
||||
copy $f1, $f or die "ERROR: $f1 $f: $!";
|
||||
|
||||
require T_L10N;
|
||||
@_ = qw();
|
||||
$_ = T_L10N->get_handle("en");
|
||||
$_->bindtextdomain("test_reload", $LOCALEDIR);
|
||||
$_->textdomain("test_reload");
|
||||
$_[0] = $_->maketext("Hello, world!");
|
||||
$_[1] = $_->maketext("Every story has a happy ending.");
|
||||
unlink $f;
|
||||
copy $f2, $f or die "ERROR: $f2 $f: $!";
|
||||
$_[2] = $_->maketext("Hello, world!");
|
||||
$_[3] = $_->maketext("Every story has a happy ending.");
|
||||
$_->reload_text;
|
||||
$_[4] = $_->maketext("Hello, world!");
|
||||
$_[5] = $_->maketext("Every story has a happy ending.");
|
||||
|
||||
unlink $f;
|
||||
return 1;
|
||||
};
|
||||
# 19
|
||||
ok($r, 1);
|
||||
# 20
|
||||
ok($_[0], "Hiya :)");
|
||||
# 21
|
||||
ok($_[1], "Every story has a happy ending.");
|
||||
# 22
|
||||
ok($_[2], "Hiya :)");
|
||||
# 23
|
||||
ok($_[3], "Every story has a happy ending.");
|
||||
# 24
|
||||
ok($_[4], "Hello, world!");
|
||||
# 25
|
||||
ok($_[5], "Pray it.");
|
||||
|
||||
# Garbage collection
|
||||
unlink catfile($LOCALEDIR, "en", "LC_MESSAGES", "test_reload.mo");
|
317
t/06-racing.t
Executable file
317
t/06-racing.t
Executable file
@ -0,0 +1,317 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Test suite for the hybrid racing condition
|
||||
# Copyright (c) 2003-2007 imacat. All rights reserved. This program is free
|
||||
# software; you can redistribute it and/or modify it under the same terms
|
||||
# as Perl itself.
|
||||
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test;
|
||||
|
||||
BEGIN { plan tests => 42 }
|
||||
|
||||
use FindBin;
|
||||
use File::Spec::Functions qw(catdir catfile);
|
||||
use lib $FindBin::Bin;
|
||||
use vars qw($LOCALEDIR $r $LOOKUP_FAILURE);
|
||||
$LOCALEDIR = catdir($FindBin::Bin, "locale");
|
||||
|
||||
# Hybrid racing conditionr
|
||||
use vars qw($lh1 $lh2);
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
require T_L10N;
|
||||
|
||||
$lh1 = T_L10N->get_handle("zh-tw");
|
||||
$lh1->fail_with(sub { $LOOKUP_FAILURE = 1; die; });
|
||||
$lh1->bindtextdomain("test", $LOCALEDIR);
|
||||
$lh1->textdomain("test");
|
||||
$lh1->encoding("Big5");
|
||||
$lh1->die_for_lookup_failures(0);
|
||||
|
||||
$lh2 = T_L10N->get_handle("zh-tw");
|
||||
$lh2->fail_with(sub { $LOOKUP_FAILURE = 1; die; });
|
||||
$lh2->bindtextdomain("test2", $LOCALEDIR);
|
||||
$lh2->textdomain("test2");
|
||||
$lh2->encoding("UTF-8");
|
||||
$lh2->die_for_lookup_failures(1);
|
||||
return 1;
|
||||
};
|
||||
# 1
|
||||
ok($r, 1);
|
||||
|
||||
# Once
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh1->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 2
|
||||
ok($_, "大家好。");
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh1->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 3
|
||||
ok($_, "Every story has a happy ending.");
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh2->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 4
|
||||
ok($r, undef);
|
||||
# 5
|
||||
ok($LOOKUP_FAILURE, 1);
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh2->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 6
|
||||
ok($_, "<22><><EFBFBD><EFBFBD>賣<EFBFBD>蝢𡡞<E89DA2><F0A1A19E><EFBFBD><EFBFBD>撅<EFBFBD><E69285><EFBFBD>");
|
||||
|
||||
# Again
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh1->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 7
|
||||
ok($_, "大家好。");
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh1->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 8
|
||||
ok($_, "Every story has a happy ending.");
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh2->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 9
|
||||
ok($r, undef);
|
||||
# 10
|
||||
ok($LOOKUP_FAILURE, 1);
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh2->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 11
|
||||
ok($_, "<22><><EFBFBD><EFBFBD>賣<EFBFBD>蝢𡡞<E89DA2><F0A1A19E><EFBFBD><EFBFBD>撅<EFBFBD><E69285><EFBFBD>");
|
||||
|
||||
# Exchange everything!
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$lh1->bindtextdomain("test2", $LOCALEDIR);
|
||||
$lh1->textdomain("test2");
|
||||
$lh1->encoding("UTF-8");
|
||||
$lh1->die_for_lookup_failures(1);
|
||||
|
||||
$lh2->bindtextdomain("test", $LOCALEDIR);
|
||||
$lh2->textdomain("test");
|
||||
$lh2->encoding("Big5");
|
||||
$lh2->die_for_lookup_failures(0);
|
||||
return 1;
|
||||
};
|
||||
# 12
|
||||
ok($r, 1);
|
||||
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh1->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 13
|
||||
ok($r, undef);
|
||||
# 14
|
||||
ok($LOOKUP_FAILURE, 1);
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh1->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 15
|
||||
ok($_, "<22><><EFBFBD><EFBFBD>賣<EFBFBD>蝢𡡞<E89DA2><F0A1A19E><EFBFBD><EFBFBD>撅<EFBFBD><E69285><EFBFBD>");
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh2->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 16
|
||||
ok($_, "大家好。");
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh2->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 17
|
||||
ok($_, "Every story has a happy ending.");
|
||||
|
||||
# Exchange the text domains
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$lh1->textdomain("test");
|
||||
$lh2->textdomain("test2");
|
||||
return 1;
|
||||
};
|
||||
# 18
|
||||
ok($r, 1);
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh1->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 19
|
||||
ok($_, "憭批振憟賬<E6869F><E8B3AC>");
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh1->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 20
|
||||
ok($r, undef);
|
||||
# 21
|
||||
ok($LOOKUP_FAILURE, 1);
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh2->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 22
|
||||
ok($_, "Hello, world!");
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh2->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 23
|
||||
ok($_, "故事都有美麗的結局。");
|
||||
|
||||
# Exchange encodings
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$lh1->encoding("Big5");
|
||||
$lh2->encoding("UTF-8");
|
||||
return 1;
|
||||
};
|
||||
# 24
|
||||
ok($r, 1);
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh1->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 25
|
||||
ok($_, "大家好。");
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh1->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 26
|
||||
ok($r, undef);
|
||||
# 27
|
||||
ok($LOOKUP_FAILURE, 1);
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh2->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 28
|
||||
ok($_, "Hello, world!");
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh2->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 29
|
||||
ok($_, "<22><><EFBFBD><EFBFBD>賣<EFBFBD>蝢𡡞<E89DA2><F0A1A19E><EFBFBD><EFBFBD>撅<EFBFBD><E69285><EFBFBD>");
|
||||
|
||||
# Exchange lookup-failure behaviors
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$lh1->die_for_lookup_failures(0);
|
||||
$lh2->die_for_lookup_failures(1);
|
||||
return 1;
|
||||
};
|
||||
# 30
|
||||
ok($r, 1);
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh1->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 31
|
||||
ok($_, "大家好。");
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh1->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 32
|
||||
ok($_, "Every story has a happy ending.");
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh2->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
|
||||
# 33
|
||||
ok($r, undef);
|
||||
# 34
|
||||
ok($LOOKUP_FAILURE, 1);
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh2->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 35
|
||||
ok($_, "<22><><EFBFBD><EFBFBD>賣<EFBFBD>蝢𡡞<E89DA2><F0A1A19E><EFBFBD><EFBFBD>撅<EFBFBD><E69285><EFBFBD>");
|
||||
|
||||
# Switch to an non-existing domain
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$lh1->textdomain("Big5");
|
||||
$lh2->textdomain("GB2312");
|
||||
return 1;
|
||||
};
|
||||
# 36
|
||||
ok($r, 1);
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh1->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 37
|
||||
ok($_, "Hello, world!");
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh1->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 38
|
||||
ok($_, "Every story has a happy ending.");
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh2->maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 39
|
||||
ok($r, undef);
|
||||
# 40
|
||||
ok($LOOKUP_FAILURE, 1);
|
||||
$r = eval {
|
||||
undef $LOOKUP_FAILURE;
|
||||
$_ = $lh2->maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 41
|
||||
ok($r, undef);
|
||||
# 42
|
||||
ok($LOOKUP_FAILURE, 1);
|
275
t/07-f-basic.t
Executable file
275
t/07-f-basic.t
Executable file
@ -0,0 +1,275 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Basic test suite for the functional interface
|
||||
# Copyright (c) 2003-2008 imacat. All rights reserved. This program is free
|
||||
# software; you can redistribute it and/or modify it under the same terms
|
||||
# as Perl itself.
|
||||
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test;
|
||||
|
||||
BEGIN { plan tests => 41 }
|
||||
|
||||
use FindBin;
|
||||
use File::Spec::Functions qw(catdir catfile);
|
||||
use lib $FindBin::Bin;
|
||||
use vars qw($LOCALEDIR $r);
|
||||
$LOCALEDIR = catdir($FindBin::Bin, "locale");
|
||||
delete $ENV{$_}
|
||||
foreach qw(LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES LC_NUMERIC
|
||||
LC_MONETARY LC_TIME LANG);
|
||||
|
||||
# Basic test suite
|
||||
# bindtextdomain
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
$_ = bindtextdomain("test", $LOCALEDIR);
|
||||
return 1;
|
||||
};
|
||||
# 1
|
||||
ok($r, 1);
|
||||
# 2
|
||||
ok($_, $LOCALEDIR);
|
||||
|
||||
# textdomain
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
$_ = textdomain("test");
|
||||
return 1;
|
||||
};
|
||||
# 3
|
||||
ok($r, 1);
|
||||
# 4
|
||||
ok($_, "test");
|
||||
|
||||
# get_handle
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("en");
|
||||
return 1;
|
||||
};
|
||||
# 5
|
||||
ok($r, 1);
|
||||
|
||||
# maketext
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("en");
|
||||
$_ = maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 6
|
||||
ok($r, 1);
|
||||
# 7
|
||||
ok($_, "Hiya :)");
|
||||
|
||||
# __ (shortcut to maketext)
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("en");
|
||||
$_ = __("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 8
|
||||
ok($r, 1);
|
||||
# 9
|
||||
ok($_, "Hiya :)");
|
||||
|
||||
# N_ (do nothing)
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("en");
|
||||
$_ = N_("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 10
|
||||
ok($r, 1);
|
||||
# 11
|
||||
ok($_, "Hello, world!");
|
||||
|
||||
# N_ (do nothing)
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("en");
|
||||
# 李子文你這粒大西瓜! :p (From: 台灣霹靂火)
|
||||
@_ = N_("Hello, world!", "Cool!", "Big watermelon");
|
||||
return 1;
|
||||
};
|
||||
# 12
|
||||
ok($r, 1);
|
||||
# 13
|
||||
ok($_[0], "Hello, world!");
|
||||
# 14
|
||||
ok($_[1], "Cool!");
|
||||
# 15
|
||||
ok($_[2], "Big watermelon");
|
||||
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("en");
|
||||
$_ = N_("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 16
|
||||
ok($r, 1);
|
||||
# 17
|
||||
ok($_, "Hello, world!");
|
||||
|
||||
# maketext
|
||||
# English
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
@_ = qw();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("en");
|
||||
$_[0] = __("Hello, world!");
|
||||
$_[1] = pmaketext("Menu|File|", "Hello, world!");
|
||||
$_[2] = pmaketext("Menu|View|", "Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 18
|
||||
ok($r, 1);
|
||||
# 19
|
||||
ok($_[0], "Hiya :)");
|
||||
# 20
|
||||
ok($_[1], "Hiya :) under the File menu");
|
||||
# 21
|
||||
ok($_[2], "Hiya :) under the View menu");
|
||||
|
||||
# Traditional Chinese
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
@_ = qw();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("zh-tw");
|
||||
$_[0] = __("Hello, world!");
|
||||
$_[1] = pmaketext("Menu|File|", "Hello, world!");
|
||||
$_[2] = pmaketext("Menu|View|", "Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 22
|
||||
ok($r, 1);
|
||||
# 23
|
||||
ok($_[0], "大家好。");
|
||||
# 24
|
||||
ok($_[1], "檔案選單下的大家好。");
|
||||
# 25
|
||||
ok($_[2], "瀏覽選單下的大家好。");
|
||||
|
||||
# Simplified Chinese
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
@_ = qw();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("zh-cn");
|
||||
$_[0] = __("Hello, world!");
|
||||
$_[1] = pmaketext("Menu|File|", "Hello, world!");
|
||||
$_[2] = pmaketext("Menu|View|", "Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 26
|
||||
ok($r, 1);
|
||||
# 27
|
||||
ok($_[0], "湮模疑﹝");
|
||||
# 28
|
||||
ok($_[1], "紫偶粕等狟腔湮模疑﹝");
|
||||
# 29
|
||||
ok($_[2], "銡擬粕等狟腔湮模疑﹝");
|
||||
|
||||
# maketext - by environment
|
||||
# English
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
@_ = qw();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
$ENV{"LANG"} = "en";
|
||||
get_handle();
|
||||
$_[0] = __("Hello, world!");
|
||||
$_[1] = pmaketext("Menu|File|", "Hello, world!");
|
||||
$_[2] = pmaketext("Menu|View|", "Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 30
|
||||
ok($r, 1);
|
||||
# 31
|
||||
ok($_[0], "Hiya :)");
|
||||
# 32
|
||||
ok($_[1], "Hiya :) under the File menu");
|
||||
# 33
|
||||
ok($_[2], "Hiya :) under the View menu");
|
||||
|
||||
# Traditional Chinese
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
@_ = qw();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
$ENV{"LANG"} = "zh-tw";
|
||||
get_handle();
|
||||
$_[0] = __("Hello, world!");
|
||||
$_[1] = pmaketext("Menu|File|", "Hello, world!");
|
||||
$_[2] = pmaketext("Menu|View|", "Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 34
|
||||
ok($r, 1);
|
||||
# 35
|
||||
ok($_[0], "大家好。");
|
||||
# 36
|
||||
ok($_[1], "檔案選單下的大家好。");
|
||||
# 37
|
||||
ok($_[2], "瀏覽選單下的大家好。");
|
||||
|
||||
# Simplified Chinese
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
@_ = qw();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
$ENV{"LANG"} = "zh-cn";
|
||||
get_handle();
|
||||
$_[0] = __("Hello, world!");
|
||||
$_[1] = pmaketext("Menu|File|", "Hello, world!");
|
||||
$_[2] = pmaketext("Menu|View|", "Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 38
|
||||
ok($r, 1);
|
||||
# 39
|
||||
ok($_[0], "湮模疑﹝");
|
||||
# 40
|
||||
ok($_[1], "紫偶粕等狟腔湮模疑﹝");
|
||||
# 41
|
||||
ok($_[2], "銡擬粕等狟腔湮模疑﹝");
|
344
t/08-f-errors.t
Executable file
344
t/08-f-errors.t
Executable file
@ -0,0 +1,344 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Test suite on the functional interface for the behavior when something goes wrong
|
||||
# Copyright (c) 2003-2008 imacat. All rights reserved. This program is free
|
||||
# software; you can redistribute it and/or modify it under the same terms
|
||||
# as Perl itself.
|
||||
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test;
|
||||
|
||||
BEGIN { plan tests => 39 }
|
||||
|
||||
use Encode qw();
|
||||
use FindBin;
|
||||
use File::Basename qw(basename);
|
||||
use File::Spec::Functions qw(catdir catfile);
|
||||
use lib $FindBin::Bin;
|
||||
use vars qw($THIS_FILE $LOCALEDIR $r);
|
||||
$THIS_FILE = basename($0);
|
||||
$LOCALEDIR = catdir($FindBin::Bin, "locale");
|
||||
sub find_system_mo();
|
||||
|
||||
# find_system_mo: Find a safe system MO to be tested
|
||||
sub find_system_mo() {
|
||||
local ($_, %_);
|
||||
my %cands;
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
# Find all the system MO files
|
||||
%cands = qw();
|
||||
foreach my $dir (@Locale::Maketext::Gettext::Functions::SYSTEM_LOCALEDIRS) {
|
||||
my ($DH, @langs);
|
||||
next unless -d $dir;
|
||||
|
||||
@langs = qw();
|
||||
opendir $DH, $dir or die "$THIS_FILE: $dir: $!";
|
||||
while (defined($_ = readdir $DH)) {
|
||||
my $dir1;
|
||||
$dir1 = catfile($dir, $_, "LC_MESSAGES");
|
||||
push @langs, $_ if -d $dir1 && -r $dir1;
|
||||
}
|
||||
closedir $DH or die "$THIS_FILE: $dir: $!";
|
||||
|
||||
foreach my $lang (sort @langs) {
|
||||
my $dir1;
|
||||
$dir1 = catfile($dir, $lang, "LC_MESSAGES");
|
||||
opendir $DH, $dir1 or die "$THIS_FILE: $dir1: $!";
|
||||
while (defined($_ = readdir $DH)) {
|
||||
my ($file, $domain);
|
||||
$file = catfile($dir1, $_);
|
||||
next unless -f $file && -r $file && /^(.+)\.mo$/;
|
||||
$domain = $1;
|
||||
$cands{$file} = [$lang, $domain];
|
||||
}
|
||||
closedir $DH or die "$THIS_FILE: $dir1: $!";
|
||||
}
|
||||
}
|
||||
# Check each MO file, from the newest
|
||||
foreach my $file (sort { (stat $b)[9] <=> (stat $a)[9] } keys %cands) {
|
||||
my ($FH, $size, $content, $charset, $lang, $domain);
|
||||
$size = (stat $file)[7];
|
||||
open $FH, $file or die "$THIS_FILE: $file: $!";
|
||||
read $FH, $content, $size or die "$THIS_FILE: $file: $!";
|
||||
close $FH or die "$THIS_FILE: $file: $!";
|
||||
next unless $content =~ /Project-Id-Version:/;
|
||||
next unless $content =~ /\s+charset=([^\n]+)/;
|
||||
$charset = $1;
|
||||
next unless defined Encode::resolve_alias($charset);
|
||||
# OK. We take this one
|
||||
($lang, $domain) = @{$cands{$file}};
|
||||
$lang = lc $lang;
|
||||
$lang =~ s/_/-/g;
|
||||
$lang = "i-default" if $lang eq "c";
|
||||
return ($lang, $domain);
|
||||
}
|
||||
# Not found
|
||||
return (undef, undef);
|
||||
}
|
||||
|
||||
# When something goes wrong
|
||||
use vars qw($dir $domain $lang $skip);
|
||||
# GNU gettext never fails!
|
||||
# bindtextdomain
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
$_ = bindtextdomain("test");
|
||||
return 1;
|
||||
};
|
||||
# 1
|
||||
ok($r, 1);
|
||||
# 2
|
||||
ok($_, undef);
|
||||
|
||||
# textdomain
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
$_ = textdomain;
|
||||
return 1;
|
||||
};
|
||||
# 3
|
||||
ok($r, 1);
|
||||
# 4
|
||||
ok($_, undef);
|
||||
|
||||
# No text domain claimed yet
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
$_ = __("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 5
|
||||
ok($r, 1);
|
||||
# 6
|
||||
ok($_, "Hello, world!");
|
||||
|
||||
# Non-existing LOCALEDIR
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", "/dev/null");
|
||||
textdomain("test");
|
||||
$_ = __("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 7
|
||||
ok($r, 1);
|
||||
# 8
|
||||
ok($_, "Hello, world!");
|
||||
|
||||
# Not-registered DOMAIN
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
textdomain("not_registered");
|
||||
$_ = __("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 9
|
||||
ok($r, 1);
|
||||
# 10
|
||||
ok($_, "Hello, world!");
|
||||
|
||||
# PO file not exists
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("no_such_domain", $LOCALEDIR);
|
||||
textdomain("no_such_domain");
|
||||
$_ = __("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 11
|
||||
ok($r, 1);
|
||||
# 12
|
||||
ok($_, "Hello, world!");
|
||||
|
||||
# PO file invalid
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("bad", $LOCALEDIR);
|
||||
textdomain("bad");
|
||||
$_ = __("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 13
|
||||
ok($r, 1);
|
||||
# 14
|
||||
ok($_, "Hello, world!");
|
||||
|
||||
# No such message
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
@_ = qw();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("en");
|
||||
$_[0] = __("[*,_1,non-existing message,non-existing messages]", 1);
|
||||
$_[1] = __("[*,_1,non-existing message,non-existing messages]", 3);
|
||||
$_[2] = pmaketext("Menu|View|", "[*,_1,non-existing message,non-existing messages]", 1);
|
||||
$_[3] = pmaketext("Menu|View|", "[*,_1,non-existing message,non-existing messages]", 3);
|
||||
$_[4] = pmaketext("Menu|None|", "Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 15
|
||||
ok($r, 1);
|
||||
# 16
|
||||
ok($_[0], "1 non-existing message");
|
||||
# 17
|
||||
ok($_[1], "3 non-existing messages");
|
||||
# 18
|
||||
ok($_[2], "1 non-existing message");
|
||||
# 19
|
||||
ok($_[3], "3 non-existing messages");
|
||||
# 20
|
||||
ok($_[4], "Hello, world!");
|
||||
|
||||
# get_handle before textdomain
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
get_handle("en");
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
$_ = __("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 21
|
||||
ok($r, 1);
|
||||
# 22
|
||||
ok($_, "Hiya :)");
|
||||
|
||||
# bindtextdomain after textdomain
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
get_handle("en");
|
||||
textdomain("test2");
|
||||
bindtextdomain("test2", $LOCALEDIR);
|
||||
$_ = __("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 23
|
||||
ok($r, 1);
|
||||
# 24
|
||||
ok($_, "Pray it.");
|
||||
|
||||
# multibyte keys
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("zh-tw");
|
||||
key_encoding("Big5");
|
||||
$_ = maketext("¡]¥¼³]©w¡^");
|
||||
return 1;
|
||||
};
|
||||
# 25
|
||||
ok($r, 1);
|
||||
# 26
|
||||
ok($_, "¡]¥¼³]©w¡^");
|
||||
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", "/dev/null");
|
||||
textdomain("test");
|
||||
get_handle("zh-tw");
|
||||
key_encoding("Big5");
|
||||
$_ = maketext("¡]¥¼³]©w¡^");
|
||||
return 1;
|
||||
};
|
||||
# 27
|
||||
ok($r, 1);
|
||||
# 28
|
||||
ok($_, "¡]¥¼³]©w¡^");
|
||||
|
||||
# Maketext before and after binding text domain
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
__("Hello, world!");
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("en");
|
||||
$_ = __("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 29
|
||||
ok($r, 1);
|
||||
# 30
|
||||
ok($_, "Hiya :)");
|
||||
|
||||
# Switch to a domain that is not binded yet
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
get_handle("en");
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
textdomain("test2");
|
||||
$_ = __("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 31
|
||||
ok($r, 1);
|
||||
# 32
|
||||
ok($_, "Hello, world!");
|
||||
|
||||
# N_: different context - string to array
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("en");
|
||||
@_ = N_("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 33
|
||||
ok($r, 1);
|
||||
# 34
|
||||
ok($_[0], "Hello, world!");
|
||||
# 35
|
||||
ok($_[1], undef);
|
||||
|
||||
# N_: different context - array to string
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("en");
|
||||
$_ = N_("Hello, world!", "Cool!", "Big watermelon");
|
||||
return 1;
|
||||
};
|
||||
# 36
|
||||
ok($r, 1);
|
||||
# 37
|
||||
ok($_, "Hello, world!");
|
||||
|
||||
# Search system locale directories
|
||||
($lang, $domain) = find_system_mo;
|
||||
$skip = defined $domain? 0: 1;
|
||||
$r = eval {
|
||||
return if $skip;
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
textdomain($domain);
|
||||
get_handle($lang);
|
||||
$_ = maketext("");
|
||||
# Skip if $Lexicon{""} does not exists
|
||||
$skip = 1 if $_ eq "";
|
||||
return 1;
|
||||
};
|
||||
# 38
|
||||
skip($skip, $r, 1, $@);
|
||||
# 39
|
||||
skip($skip, $_, qr/Project-Id-Version:/);
|
282
t/09-f-encodings.t
Executable file
282
t/09-f-encodings.t
Executable file
@ -0,0 +1,282 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Test suite on the functional interface for different encodings
|
||||
# Copyright (c) 2003-2007 imacat. All rights reserved. This program is free
|
||||
# software; you can redistribute it and/or modify it under the same terms
|
||||
# as Perl itself.
|
||||
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test;
|
||||
|
||||
BEGIN { plan tests => 34 }
|
||||
|
||||
use Encode qw();
|
||||
use FindBin;
|
||||
use File::Spec::Functions qw(catdir);
|
||||
use lib $FindBin::Bin;
|
||||
use vars qw($LOCALEDIR $r);
|
||||
$LOCALEDIR = catdir($FindBin::Bin, "locale");
|
||||
|
||||
# Different encodings
|
||||
# English
|
||||
# Find the default encoding
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("en");
|
||||
$_ = encoding();
|
||||
return 1;
|
||||
};
|
||||
# 1
|
||||
ok($r, 1);
|
||||
# 2
|
||||
ok($_, "US-ASCII");
|
||||
|
||||
# Traditional Chinese
|
||||
# Find the default encoding
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("zh-tw");
|
||||
$_ = encoding();
|
||||
return 1;
|
||||
};
|
||||
# 3
|
||||
ok($r, 1);
|
||||
# 4
|
||||
ok($_, "Big5");
|
||||
|
||||
# Turn to Big5
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("zh-tw");
|
||||
encoding("Big5");
|
||||
$_ = maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 5
|
||||
ok($r, 1);
|
||||
# 6
|
||||
ok($_, "<22>產<EFBFBD><E794A2>");
|
||||
|
||||
# Turn to UTF-8
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("zh-tw");
|
||||
encoding("UTF-8");
|
||||
$_ = maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 7
|
||||
ok($r, 1);
|
||||
# 8
|
||||
ok($_, "澶у<E6BEB6>濂姐€<E5A790>");
|
||||
|
||||
# Turn to UTF-16LE
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("zh-tw");
|
||||
encoding("UTF-16LE");
|
||||
$_ = maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 9
|
||||
ok($r, 1);
|
||||
# 10
|
||||
ok($_, "'Y禰}Y0");
|
||||
|
||||
# Find the default encoding, in UTF-8
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test_utf8", $LOCALEDIR);
|
||||
textdomain("test_utf8");
|
||||
get_handle("zh-tw");
|
||||
$_ = encoding();
|
||||
return 1;
|
||||
};
|
||||
# 11
|
||||
ok($r, 1);
|
||||
# 12
|
||||
ok($_, "UTF-8");
|
||||
|
||||
# Turn to UTF-8
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test_utf8", $LOCALEDIR);
|
||||
textdomain("test_utf8");
|
||||
get_handle("zh-tw");
|
||||
encoding("UTF-8");
|
||||
$_ = maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 13
|
||||
ok($r, 1);
|
||||
# 14
|
||||
ok($_, "澶у<E6BEB6>濂姐€<E5A790>");
|
||||
|
||||
# Turn to Big5
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test_utf8", $LOCALEDIR);
|
||||
textdomain("test_utf8");
|
||||
get_handle("zh-tw");
|
||||
encoding("Big5");
|
||||
$_ = maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 15
|
||||
ok($r, 1);
|
||||
# 16
|
||||
ok($_, "<22>產<EFBFBD><E794A2>");
|
||||
|
||||
# Turn to UTF-16LE
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test_utf8", $LOCALEDIR);
|
||||
textdomain("test_utf8");
|
||||
get_handle("zh-tw");
|
||||
encoding("UTF-16LE");
|
||||
$_ = maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 17
|
||||
ok($r, 1);
|
||||
# 18
|
||||
ok($_, "'Y禰}Y0");
|
||||
|
||||
# Find the default encoding
|
||||
# Simplified Chinese
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test_utf8", $LOCALEDIR);
|
||||
textdomain("test_utf8");
|
||||
get_handle("zh-cn");
|
||||
$_ = encoding();
|
||||
return 1;
|
||||
};
|
||||
# 19
|
||||
ok($r, 1);
|
||||
# 20
|
||||
ok($_, "UTF-8");
|
||||
|
||||
# Turn to GB2312
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test_utf8", $LOCALEDIR);
|
||||
textdomain("test_utf8");
|
||||
get_handle("zh-cn");
|
||||
encoding("GB2312");
|
||||
$_ = maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 21
|
||||
ok($r, 1);
|
||||
# 22
|
||||
ok($_, "大家好。");
|
||||
|
||||
# Encode failure
|
||||
# FB_DEFAULT
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test2", $LOCALEDIR);
|
||||
textdomain("test2");
|
||||
get_handle("zh-tw");
|
||||
encoding("GB2312");
|
||||
$_ = maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 23
|
||||
ok($r, 1);
|
||||
# 24
|
||||
ok($_, "故事都有美?的?局。");
|
||||
|
||||
# FB_CROAK
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test2", $LOCALEDIR);
|
||||
textdomain("test2");
|
||||
get_handle("zh-tw");
|
||||
encoding("GB2312");
|
||||
encode_failure(Encode::FB_CROAK);
|
||||
$_ = maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 25
|
||||
ok($r, undef);
|
||||
# 26
|
||||
ok($@, qr/does not map to/);
|
||||
|
||||
# FB_HTMLCREF
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test2", $LOCALEDIR);
|
||||
textdomain("test2");
|
||||
get_handle("zh-tw");
|
||||
encoding("GB2312");
|
||||
encode_failure(Encode::FB_HTMLCREF);
|
||||
$_ = maketext("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 27
|
||||
ok($r, 1);
|
||||
# 28
|
||||
ok($_, "故事都有美麗的結局。");
|
||||
|
||||
# Return the unencoded UTF-8 text
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("zh-tw");
|
||||
encoding(undef);
|
||||
$_ = maketext("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 29
|
||||
ok($r, 1);
|
||||
# 30
|
||||
ok($_, "\x{5927}\x{5BB6}\x{597D}\x{3002}");
|
||||
# 31
|
||||
ok((Encode::is_utf8($_)? "utf8": "non-utf8"), "utf8");
|
||||
|
||||
# Return the unencoded UTF-8 text with auto lexicon
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("zh-tw");
|
||||
encoding(undef);
|
||||
$_ = maketext("Big watermelon");
|
||||
return 1;
|
||||
};
|
||||
# 32
|
||||
ok($r, 1);
|
||||
# 33
|
||||
ok($_, "Big watermelon");
|
||||
# 34
|
||||
ok((Encode::is_utf8($_)? "utf8": "non-utf8"), "utf8");
|
416
t/10-f-switching.t
Executable file
416
t/10-f-switching.t
Executable file
@ -0,0 +1,416 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Test suite on the functional interface for switching between different settings
|
||||
# Copyright (c) 2003-2008 imacat. All rights reserved. This program is free
|
||||
# software; you can redistribute it and/or modify it under the same terms
|
||||
# as Perl itself.
|
||||
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test;
|
||||
|
||||
BEGIN { plan tests => 63 }
|
||||
|
||||
use FindBin;
|
||||
use File::Spec::Functions qw(catdir catfile);
|
||||
use lib $FindBin::Bin;
|
||||
use vars qw($LOCALEDIR $r);
|
||||
$LOCALEDIR = catdir($FindBin::Bin, "locale");
|
||||
delete $ENV{$_}
|
||||
foreach qw(LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES LC_NUMERIC
|
||||
LC_MONETARY LC_TIME LANG);
|
||||
|
||||
# Switching between different settings
|
||||
use File::Copy qw(copy);
|
||||
use vars qw($dir1 $dir2 $dir3 $f1 $f11 $f12 $f2 $f21 $f3 $f31 $class);
|
||||
|
||||
# dmaketext in the middle
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
@_ = qw();
|
||||
get_handle("en");
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
bindtextdomain("test2", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
$_[0] = __("Hello, world!");
|
||||
$_[1] = pmaketext("Menu|File|", "Hello, world!");
|
||||
$_[2] = __("Every story has a happy ending.");
|
||||
$_[3] = pmaketext("Menu|File|", "Every story has a happy ending.");
|
||||
$_[4] = dmaketext("test2", "Hello, world!");
|
||||
$_[5] = dpmaketext("test2", "Menu|File|", "Hello, world!");
|
||||
$_[6] = dmaketext("test2", "Every story has a happy ending.");
|
||||
$_[7] = dpmaketext("test2", "Menu|File|", "Every story has a happy ending.");
|
||||
$_[8] = __("Hello, world!");
|
||||
$_[9] = pmaketext("Menu|File|", "Hello, world!");
|
||||
$_[10] = __("Every story has a happy ending.");
|
||||
$_[11] = pmaketext("Menu|File|", "Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 1
|
||||
ok($r, 1);
|
||||
# 2
|
||||
ok($_[0], "Hiya :)");
|
||||
# 3
|
||||
ok($_[1], "Hiya :) under the File menu");
|
||||
# 4
|
||||
ok($_[2], "Every story has a happy ending.");
|
||||
# 5
|
||||
ok($_[3], "Every story has a happy ending.");
|
||||
# 6
|
||||
ok($_[4], "Hello, world!");
|
||||
# 6
|
||||
ok($_[5], "Hello, world!");
|
||||
# 8
|
||||
ok($_[6], "Pray it.");
|
||||
# 9
|
||||
ok($_[7], "Pray it under the File menu");
|
||||
# 10
|
||||
ok($_[8], "Hiya :)");
|
||||
# 11
|
||||
ok($_[9], "Hiya :) under the File menu");
|
||||
# 12
|
||||
ok($_[10], "Every story has a happy ending.");
|
||||
# 13
|
||||
ok($_[11], "Every story has a happy ending.");
|
||||
|
||||
# Switch between domains
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
@_ = qw();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
bindtextdomain("test2", $LOCALEDIR);
|
||||
get_handle("en");
|
||||
textdomain("test");
|
||||
$_[0] = __("Hello, world!");
|
||||
$_[1] = __("Every story has a happy ending.");
|
||||
textdomain("test2");
|
||||
$_[2] = __("Hello, world!");
|
||||
$_[3] = __("Every story has a happy ending.");
|
||||
textdomain("test");
|
||||
$_[4] = __("Hello, world!");
|
||||
$_[5] = __("Every story has a happy ending.");
|
||||
return 1;
|
||||
};
|
||||
# 14
|
||||
ok($r, 1);
|
||||
# 15
|
||||
ok($_[0], "Hiya :)");
|
||||
# 16
|
||||
ok($_[1], "Every story has a happy ending.");
|
||||
# 17
|
||||
ok($_[2], "Hello, world!");
|
||||
# 18
|
||||
ok($_[3], "Pray it.");
|
||||
# 19
|
||||
ok($_[4], "Hiya :)");
|
||||
# 20
|
||||
ok($_[5], "Every story has a happy ending.");
|
||||
|
||||
# Switch between languages
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
@_ = qw();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("en");
|
||||
$_[0] = __("Hello, world!");
|
||||
get_handle("zh-tw");
|
||||
$_[1] = __("Hello, world!");
|
||||
get_handle("zh-cn");
|
||||
$_[2] = __("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 21
|
||||
ok($r, 1);
|
||||
# 22
|
||||
ok($_[0], "Hiya :)");
|
||||
# 23
|
||||
ok($_[1], "大家好。");
|
||||
# 24
|
||||
ok($_[2], "湮模疑﹝");
|
||||
|
||||
# Switch between languages - by environment
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
@_ = qw();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
$ENV{"LANG"} = "en";
|
||||
get_handle();
|
||||
$_[0] = __("Hello, world!");
|
||||
$ENV{"LANG"} = "zh-tw";
|
||||
get_handle();
|
||||
$_[1] = __("Hello, world!");
|
||||
$ENV{"LANG"} = "zh-cn";
|
||||
get_handle();
|
||||
$_[2] = __("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 25
|
||||
ok($r, 1);
|
||||
# 26
|
||||
ok($_[0], "Hiya :)");
|
||||
# 27
|
||||
ok($_[1], "大家好。");
|
||||
# 28
|
||||
ok($_[2], "湮模疑﹝");
|
||||
|
||||
# Switch between different language methods
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
@_ = qw();
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("en");
|
||||
$_[0] = __("Hello, world!");
|
||||
$ENV{"LANG"} = "zh-tw";
|
||||
get_handle();
|
||||
$_[1] = __("Hello, world!");
|
||||
get_handle("zh-cn");
|
||||
$_[2] = __("Hello, world!");
|
||||
$ENV{"LANG"} = "en";
|
||||
get_handle();
|
||||
$_[3] = __("Hello, world!");
|
||||
return 1;
|
||||
};
|
||||
# 29
|
||||
ok($r, 1);
|
||||
# 30
|
||||
ok($_[0], "Hiya :)");
|
||||
# 31
|
||||
ok($_[1], "大家好。");
|
||||
# 32
|
||||
ok($_[2], "湮模疑﹝");
|
||||
# 33
|
||||
ok($_[3], "Hiya :)");
|
||||
|
||||
# Reuse of a same text domain class
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
@_ = qw();
|
||||
$ENV{"LANG"} = "en";
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle();
|
||||
$_[0] = __("Hello, world!");
|
||||
$_[1] = __("Every story has a happy ending.");
|
||||
$_[2] = ref($Locale::Maketext::Gettext::Functions::LH);
|
||||
$_[2] =~ s/^(.+)::.*?$/$1/;
|
||||
|
||||
bindtextdomain("test2", $LOCALEDIR);
|
||||
textdomain("test2");
|
||||
get_handle("zh-tw");
|
||||
$_[3] = __("Hello, world!");
|
||||
$_[4] = __("Every story has a happy ending.");
|
||||
|
||||
bindtextdomain("test", "/dev/null");
|
||||
textdomain("test");
|
||||
get_handle("en");
|
||||
$_[5] = __("Hello, world!");
|
||||
$_[6] = __("Every story has a happy ending.");
|
||||
|
||||
bindtextdomain("test", $LOCALEDIR);
|
||||
textdomain("test");
|
||||
get_handle("zh-cn");
|
||||
$_[7] = __("Hello, world!");
|
||||
$_[8] = __("Every story has a happy ending.");
|
||||
$_[9] = ref($Locale::Maketext::Gettext::Functions::LH);
|
||||
$_[9] =~ s/^(.+)::.*?$/$1/;
|
||||
return 1;
|
||||
};
|
||||
# 34
|
||||
ok($r, 1);
|
||||
# 35
|
||||
ok($_[0], "Hiya :)");
|
||||
# 36
|
||||
ok($_[1], "Every story has a happy ending.");
|
||||
# 37
|
||||
ok($_[3], "Hello, world!");
|
||||
# 38
|
||||
ok($_[4], "故事都有美麗的結局。");
|
||||
# 39
|
||||
ok($_[5], "Hello, world!");
|
||||
# 40
|
||||
ok($_[6], "Every story has a happy ending.");
|
||||
# 41
|
||||
ok($_[7], "湮模疑﹝");
|
||||
# 42
|
||||
ok($_[8], "Every story has a happy ending.");
|
||||
# 43
|
||||
ok($_[2], $_[9]);
|
||||
|
||||
# Language addition/removal
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
@_ = qw();
|
||||
$dir1 = catdir($LOCALEDIR, "en", "LC_MESSAGES");
|
||||
$dir2 = catdir($LOCALEDIR, "zh_TW", "LC_MESSAGES");
|
||||
$dir3 = catdir($LOCALEDIR, "zh_CN", "LC_MESSAGES");
|
||||
$f1 = catfile($dir1, "test_dyn.mo");
|
||||
$f11 = catfile($dir1, "test.mo");
|
||||
$f2 = catfile($dir2, "test_dyn.mo");
|
||||
$f21 = catfile($dir2, "test.mo");
|
||||
$f3 = catfile($dir3, "test_dyn.mo");
|
||||
$f31 = catfile($dir3, "test.mo");
|
||||
unlink $f1;
|
||||
unlink $f2;
|
||||
unlink $f3;
|
||||
|
||||
bindtextdomain("test_dyn", $LOCALEDIR);
|
||||
textdomain("test_dyn");
|
||||
get_handle("zh-tw");
|
||||
$_[0] = __("Hello, world!");
|
||||
get_handle("zh-cn");
|
||||
$_[1] = __("Hello, world!");
|
||||
|
||||
copy $f21, $f2 or die "ERROR: $f21 $f2: $!";
|
||||
textdomain("test_dyn");
|
||||
get_handle("zh-tw");
|
||||
$_[2] = __("Hello, world!");
|
||||
get_handle("zh-cn");
|
||||
$_[3] = __("Hello, world!");
|
||||
|
||||
unlink $f2;
|
||||
copy $f31, $f3 or die "ERROR: $f31 $f3: $!";
|
||||
textdomain("test_dyn");
|
||||
get_handle("zh-tw");
|
||||
$_[4] = __("Hello, world!");
|
||||
get_handle("zh-cn");
|
||||
$_[5] = __("Hello, world!");
|
||||
|
||||
copy $f21, $f2 or die "ERROR: $f21 $f2: $!";
|
||||
textdomain("test_dyn");
|
||||
get_handle("zh-tw");
|
||||
$_[6] = __("Hello, world!");
|
||||
get_handle("zh-cn");
|
||||
$_[7] = __("Hello, world!");
|
||||
|
||||
unlink $f2;
|
||||
unlink $f3;
|
||||
textdomain("test_dyn");
|
||||
get_handle("zh-tw");
|
||||
$_[8] = __("Hello, world!");
|
||||
get_handle("zh-cn");
|
||||
$_[9] = __("Hello, world!");
|
||||
|
||||
unlink $f1;
|
||||
unlink $f2;
|
||||
unlink $f3;
|
||||
return 1;
|
||||
};
|
||||
# 44
|
||||
ok($r, 1);
|
||||
# 45
|
||||
ok($_[0], "Hello, world!");
|
||||
# 46
|
||||
ok($_[1], "Hello, world!");
|
||||
# 47
|
||||
ok($_[2], "大家好。");
|
||||
# 48
|
||||
ok($_[3], "Hello, world!");
|
||||
# 49
|
||||
ok($_[4], "Hello, world!");
|
||||
# 50
|
||||
ok($_[5], "湮模疑﹝");
|
||||
# 51
|
||||
ok($_[6], "大家好。");
|
||||
# 52
|
||||
ok($_[7], "湮模疑﹝");
|
||||
# 53
|
||||
ok($_[8], "Hello, world!");
|
||||
# 54
|
||||
ok($_[9], "Hello, world!");
|
||||
|
||||
# Garbage collection - drop abandoned language handles
|
||||
$r = eval {
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
$dir1 = catdir($LOCALEDIR, "en", "LC_MESSAGES");
|
||||
$dir2 = catdir($LOCALEDIR, "zh_TW", "LC_MESSAGES");
|
||||
$dir3 = catdir($LOCALEDIR, "zh_CN", "LC_MESSAGES");
|
||||
$f1 = catfile($dir1, "test_dyn.mo");
|
||||
$f11 = catfile($dir1, "test.mo");
|
||||
$f2 = catfile($dir2, "test_dyn.mo");
|
||||
$f21 = catfile($dir2, "test.mo");
|
||||
$f3 = catfile($dir3, "test_dyn.mo");
|
||||
$f31 = catfile($dir3, "test.mo");
|
||||
unlink $f1;
|
||||
unlink $f2;
|
||||
unlink $f3;
|
||||
|
||||
copy $f11, $f1 or die "ERROR: $f11 $f1: $!";
|
||||
copy $f21, $f2 or die "ERROR: $f21 $f2: $!";
|
||||
textdomain("test_dyn");
|
||||
get_handle("en");
|
||||
get_handle("zh-tw");
|
||||
get_handle("zh-cn");
|
||||
$class = ref($Locale::Maketext::Gettext::Functions::LH);
|
||||
$class =~ s/^(.+)::.*?$/$1/;
|
||||
|
||||
unlink $f2;
|
||||
copy $f31, $f3 or die "ERROR: $f31 $f3: $!";
|
||||
textdomain("test_dyn");
|
||||
get_handle("en");
|
||||
get_handle("zh-tw");
|
||||
get_handle("zh-cn");
|
||||
@_ = grep /^$class/, keys %Locale::Maketext::Gettext::Functions::LHS;
|
||||
return 1;
|
||||
};
|
||||
# 55
|
||||
ok($r, 1);
|
||||
# 56
|
||||
ok(scalar(@_), 0);
|
||||
|
||||
# Reload the text
|
||||
$r = eval {
|
||||
$dir1 = catdir($LOCALEDIR, "en", "LC_MESSAGES");
|
||||
$f1 = catfile($dir1, "test_reload.mo");
|
||||
$f11 = catfile($dir1, "test.mo");
|
||||
$f12 = catfile($dir1, "test2.mo");
|
||||
unlink $f1;
|
||||
copy $f11, $f1 or die "ERROR: $f11 $f1: $!";
|
||||
use Locale::Maketext::Gettext::Functions;
|
||||
Locale::Maketext::Gettext::Functions::_reset();
|
||||
@_ = qw();
|
||||
bindtextdomain("test_reload", $LOCALEDIR);
|
||||
textdomain("test_reload");
|
||||
get_handle("en");
|
||||
$_[0] = __("Hello, world!");
|
||||
$_[1] = __("Every story has a happy ending.");
|
||||
unlink $f1;
|
||||
copy $f12, $f1 or die "ERROR: $f12 $f1: $!";
|
||||
$_[2] = __("Hello, world!");
|
||||
$_[3] = __("Every story has a happy ending.");
|
||||
reload_text;
|
||||
$_[4] = __("Hello, world!");
|
||||
$_[5] = __("Every story has a happy ending.");
|
||||
unlink $f1;
|
||||
return 1;
|
||||
};
|
||||
# 57
|
||||
ok($r, 1);
|
||||
# 58
|
||||
ok($_[0], "Hiya :)");
|
||||
# 59
|
||||
ok($_[1], "Every story has a happy ending.");
|
||||
# 60
|
||||
ok($_[2], "Hiya :)");
|
||||
# 61
|
||||
ok($_[3], "Every story has a happy ending.");
|
||||
# 62
|
||||
ok($_[4], "Hello, world!");
|
||||
# 63
|
||||
ok($_[5], "Pray it.");
|
||||
|
||||
# Garbage collection
|
||||
unlink catfile($LOCALEDIR, "en", "LC_MESSAGES", "test_dyn.mo");
|
||||
unlink catfile($LOCALEDIR, "zh_TW", "LC_MESSAGES", "test_dyn.mo");
|
||||
unlink catfile($LOCALEDIR, "zh_CN", "LC_MESSAGES", "test_dyn.mo");
|
||||
unlink catfile($LOCALEDIR, "en", "LC_MESSAGES", "test_reload.mo");
|
92
t/11-command-line.t
Executable file
92
t/11-command-line.t
Executable file
@ -0,0 +1,92 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Test suite on the maketext script
|
||||
# Copyright (c) 2003-2007 imacat. All rights reserved. This program is free
|
||||
# software; you can redistribute it and/or modify it under the same terms
|
||||
# as Perl itself.
|
||||
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test;
|
||||
|
||||
BEGIN { plan tests => 10 }
|
||||
|
||||
use FindBin;
|
||||
use File::Spec::Functions qw(catdir catfile updir);
|
||||
use lib $FindBin::Bin;
|
||||
use vars qw($LOCALEDIR $r $maketext);
|
||||
$LOCALEDIR = catdir($FindBin::Bin, "locale");
|
||||
$maketext = catdir($FindBin::Bin, updir, "blib", "script", "maketext");
|
||||
|
||||
# The maketext script
|
||||
# Ordinary text unchanged
|
||||
$r = eval {
|
||||
delete $ENV{"LANG"};
|
||||
delete $ENV{"LANGUAGE"};
|
||||
delete $ENV{"TEXTDOMAINDIR"};
|
||||
delete $ENV{"TEXTDOMAIN"};
|
||||
@_ = `"$maketext" "Hello, world!"`;
|
||||
return 1;
|
||||
};
|
||||
# 1
|
||||
ok($r, 1);
|
||||
# 2
|
||||
ok($_[0], "Hello, world!");
|
||||
|
||||
# Specify the text domain by the -d argument
|
||||
# English
|
||||
$r = eval {
|
||||
$ENV{"LANG"} = "C";
|
||||
$ENV{"LANGUAGE"} = "C";
|
||||
$ENV{"TEXTDOMAINDIR"} = $LOCALEDIR;
|
||||
delete $ENV{"TEXTDOMAIN"};
|
||||
@_ = `"$maketext" -d test "Hello, world!"`;
|
||||
return 1;
|
||||
};
|
||||
# 3
|
||||
ok($r, 1);
|
||||
# 4
|
||||
ok($_[0], "Hiya :)");
|
||||
|
||||
# Specify the text domain by the environment variable
|
||||
# English
|
||||
$r = eval {
|
||||
$ENV{"LANG"} = "C";
|
||||
$ENV{"LANGUAGE"} = "C";
|
||||
$ENV{"TEXTDOMAINDIR"} = $LOCALEDIR;
|
||||
$ENV{"TEXTDOMAIN"} = "test";
|
||||
@_ = `"$maketext" "Hello, world!"`;
|
||||
return 1;
|
||||
};
|
||||
# 5
|
||||
ok($r, 1);
|
||||
# 6
|
||||
ok($_[0], "Hiya :)");
|
||||
|
||||
# The -s argument
|
||||
$r = eval {
|
||||
$ENV{"LANG"} = "C";
|
||||
$ENV{"LANGUAGE"} = "C";
|
||||
$ENV{"TEXTDOMAINDIR"} = $LOCALEDIR;
|
||||
$ENV{"TEXTDOMAIN"} = "test";
|
||||
@_ = `"$maketext" -s "Hello, world!"`;
|
||||
return 1;
|
||||
};
|
||||
# 7
|
||||
ok($r, 1);
|
||||
# 8
|
||||
ok($_[0], "Hiya :)\n");
|
||||
|
||||
# Maketext
|
||||
$r = eval {
|
||||
$ENV{"LANG"} = "C";
|
||||
$ENV{"LANGUAGE"} = "C";
|
||||
$ENV{"TEXTDOMAINDIR"} = $LOCALEDIR;
|
||||
$ENV{"TEXTDOMAIN"} = "test";
|
||||
@_ = `"$maketext" -s "[*,_1,directory,directories]" 5`;
|
||||
return 1;
|
||||
};
|
||||
# 9
|
||||
ok($r, 1);
|
||||
# 10
|
||||
ok($_[0], "5 directories\n");
|
5
t/99-pod.t
Executable file
5
t/99-pod.t
Executable file
@ -0,0 +1,5 @@
|
||||
#!/usr/bin/perl
|
||||
use Test::More;
|
||||
eval "use Test::Pod 1.00";
|
||||
plan skip_all => "Test::Pod 1.00 required for testing POD" if $@;
|
||||
all_pod_files_ok();
|
24
t/T_L10N.pm
Normal file
24
t/T_L10N.pm
Normal file
@ -0,0 +1,24 @@
|
||||
# Test localization class and its subclasses
|
||||
# Copyright (c) 2003 imacat. All rights reserved. This program is free
|
||||
# software; you can redistribute it and/or modify it under the same terms
|
||||
# as Perl itself.
|
||||
|
||||
package T_L10N;
|
||||
use base qw(Locale::Maketext::Gettext);
|
||||
|
||||
return 1;
|
||||
|
||||
package T_L10N::en;
|
||||
use base qw(Locale::Maketext::Gettext);
|
||||
|
||||
return 1;
|
||||
|
||||
package T_L10N::zh_tw;
|
||||
use base qw(Locale::Maketext::Gettext);
|
||||
|
||||
return 1;
|
||||
|
||||
package T_L10N::zh_cn;
|
||||
use base qw(Locale::Maketext::Gettext);
|
||||
|
||||
return 1;
|
BIN
t/locale/C/LC_MESSAGES/test.mo
Normal file
BIN
t/locale/C/LC_MESSAGES/test.mo
Normal file
Binary file not shown.
1
t/locale/en/LC_MESSAGES/bad.mo
Normal file
1
t/locale/en/LC_MESSAGES/bad.mo
Normal file
@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
BIN
t/locale/en/LC_MESSAGES/test.mo
Normal file
BIN
t/locale/en/LC_MESSAGES/test.mo
Normal file
Binary file not shown.
BIN
t/locale/en/LC_MESSAGES/test2.mo
Normal file
BIN
t/locale/en/LC_MESSAGES/test2.mo
Normal file
Binary file not shown.
BIN
t/locale/en/LC_MESSAGES/test_be.mo
Normal file
BIN
t/locale/en/LC_MESSAGES/test_be.mo
Normal file
Binary file not shown.
BIN
t/locale/en/LC_MESSAGES/test_utf8.mo
Normal file
BIN
t/locale/en/LC_MESSAGES/test_utf8.mo
Normal file
Binary file not shown.
BIN
t/locale/zh_CN/LC_MESSAGES/test.mo
Normal file
BIN
t/locale/zh_CN/LC_MESSAGES/test.mo
Normal file
Binary file not shown.
BIN
t/locale/zh_CN/LC_MESSAGES/test_be.mo
Normal file
BIN
t/locale/zh_CN/LC_MESSAGES/test_be.mo
Normal file
Binary file not shown.
BIN
t/locale/zh_CN/LC_MESSAGES/test_utf8.mo
Normal file
BIN
t/locale/zh_CN/LC_MESSAGES/test_utf8.mo
Normal file
Binary file not shown.
BIN
t/locale/zh_TW/LC_MESSAGES/test.mo
Normal file
BIN
t/locale/zh_TW/LC_MESSAGES/test.mo
Normal file
Binary file not shown.
BIN
t/locale/zh_TW/LC_MESSAGES/test2.mo
Normal file
BIN
t/locale/zh_TW/LC_MESSAGES/test2.mo
Normal file
Binary file not shown.
BIN
t/locale/zh_TW/LC_MESSAGES/test_be.mo
Normal file
BIN
t/locale/zh_TW/LC_MESSAGES/test_be.mo
Normal file
Binary file not shown.
BIN
t/locale/zh_TW/LC_MESSAGES/test_utf8.mo
Normal file
BIN
t/locale/zh_TW/LC_MESSAGES/test_utf8.mo
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user