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