summaryrefslogtreecommitdiff
path: root/rt/lib/RT/I18N.pm
diff options
context:
space:
mode:
Diffstat (limited to 'rt/lib/RT/I18N.pm')
-rw-r--r--rt/lib/RT/I18N.pm436
1 files changed, 0 insertions, 436 deletions
diff --git a/rt/lib/RT/I18N.pm b/rt/lib/RT/I18N.pm
deleted file mode 100644
index 79c3e8a..0000000
--- a/rt/lib/RT/I18N.pm
+++ /dev/null
@@ -1,436 +0,0 @@
-# BEGIN LICENSE BLOCK
-#
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-#
-# (Except where explictly superceded by other copyright notices)
-#
-# This work is made available to you under the terms of Version 2 of
-# the GNU General Public License. A copy of that license should have
-# been provided with this software, but in any event can be snarfed
-# from www.gnu.org.
-#
-# This work 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.
-#
-# Unless otherwise specified, all modifications, corrections or
-# extensions to this work which alter its source code become the
-# property of Best Practical Solutions, LLC when submitted for
-# inclusion in the work.
-#
-#
-# END LICENSE BLOCK
-=head1 NAME
-
-RT::I18N - a base class for localization of RT
-
-=cut
-
-package RT::I18N;
-
-use strict;
-use Locale::Maketext 1.04;
-use Locale::Maketext::Lexicon 0.25;
-use base ('Locale::Maketext::Fuzzy');
-use vars qw( %Lexicon );
-
-#If we're running on 5.6, we desperately need Encode::compat. But if we're on 5.8, we don't really need it.
-BEGIN { if ($] < 5.007001) {
-require Encode::compat;
-} }
-use Encode;
-
-use MIME::Entity;
-use MIME::Head;
-
-# I decree that this project's first language is English.
-
-%Lexicon = (
- 'TEST_STRING' => 'Concrete Mixer',
-
- '__Content-Type' => 'text/plain; charset=utf-8',
-
- '_AUTO' => 1,
- # That means that lookup failures can't happen -- if we get as far
- # as looking for something in this lexicon, and we don't find it,
- # then automagically set $Lexicon{$key} = $key, before possibly
- # compiling it.
-
- # The exception is keys that start with "_" -- they aren't auto-makeable.
-
-);
-# End of lexicon.
-
-=head2 Init
-
-Initializes the lexicons used for localization.
-
-=begin testing
-
-use_ok (RT::I18N);
-ok(RT::I18N->Init);
-
-=end testing
-
-=cut
-
-sub Init {
- # Load language-specific functions
- foreach my $language ( glob(substr(__FILE__, 0, -3) . "/*.pm")) {
- if ($language =~ /^([-\w.\/\\~:]+)$/) {
- require $1;
- }
- else {
- warn("$language is tainted. not loading");
- }
- }
-
- my @lang = @RT::LexiconLanguages;
- @lang = ('*') unless @lang;
-
- # Acquire all .po files and iterate them into lexicons
- Locale::Maketext::Lexicon->import({
- _decode => 1, map {
- $_ => [
- Gettext => (substr(__FILE__, 0, -3) . "/$_.po"),
- Gettext => "$RT::LocalLexiconPath/*/$_.po",
- ],
- } @lang
- });
-
- return 1;
-}
-
-=head2 encoding
-
-Returns the encoding of the current lexicon, as yanked out of __ContentType's "charset" field.
-If it can't find anything, it returns 'ISO-8859-1'
-
-=begin testing
-
-ok(my $chinese = RT::I18N->get_handle('zh_tw'));
-ok(UNIVERSAL::can($chinese, 'maketext'));
-ok($chinese->maketext('__Content-Type') =~ /utf-8/i, "Found the utf-8 charset for traditional chinese in the string ".$chinese->maketext('__Content-Type'));
-ok($chinese->encoding eq 'utf-8', "The encoding is 'utf-8' -".$chinese->encoding);
-
-ok(my $en = RT::I18N->get_handle('en'));
-ok(UNIVERSAL::can($en, 'maketext'));
-ok($en->encoding eq 'utf-8', "The encoding ".$en->encoding." is 'utf-8'");
-
-=end testing
-
-
-=cut
-
-
-sub encoding { 'utf-8' }
-
-# {{{ SetMIMEEntityToUTF8
-
-=head2 SetMIMEEntityToUTF8 $entity
-
-An utility method which will try to convert entity body into utf8.
-It's now a wrap-up of SetMIMEEntityToEncoding($entity, 'utf-8').
-
-=cut
-
-sub SetMIMEEntityToUTF8 {
- RT::I18N::SetMIMEEntityToEncoding(shift, 'utf-8');
-}
-
-# }}}
-
-# {{{ SetMIMEEntityToEncoding
-
-=head2 SetMIMEEntityToEncoding $entity, $encoding
-
-An utility method which will try to convert entity body into specified
-charset encoding (encoded as octets, *not* unicode-strings). It will
-iterate all the entities in $entity, and try to convert each one into
-specified charset if whose Content-Type is 'text/plain'.
-
-This method doesn't return anything meaningful.
-
-=cut
-
-sub SetMIMEEntityToEncoding {
- my ( $entity, $enc, $preserve_words ) = ( shift, shift, shift );
-
- #if ( $entity->is_multipart ) {
- #$RT::Logger->crit("This entity is a multipart " . $entity->head->as_string);
- SetMIMEEntityToEncoding( $_, $enc, $preserve_words ) foreach $entity->parts;
- #}
-
- my $charset = _FindOrGuessCharset($entity) or return;
- # one and only normalization
- $charset = 'utf-8' if $charset =~ /^utf-?8$/i;
- $enc = 'utf-8' if $enc =~ /^utf-?8$/i;
-
- SetMIMEHeadToEncoding(
- $entity->head,
- _FindOrGuessCharset($entity, 1) => $enc,
- $preserve_words
- );
-
- my $head = $entity->head;
-
- # convert at least MIME word encoded attachment filename
- foreach my $attr (qw(content-type.name content-disposition.filename)) {
- if ( my $name = $head->mime_attr($attr) and !$preserve_words ) {
- $head->mime_attr( $attr => DecodeMIMEWordsToUTF8($name) );
- }
- }
-
- # If this is a textual entity, we'd need to preserve its original encoding
- $head->add( "X-RT-Original-Encoding" => $charset )
- if $head->mime_attr('content-type.charset') or $head->mime_type =~ /^text/;
-
-
- return unless ( $head->mime_type =~ qr{^(text/plain|message/rfc822)$}i );
-
-
- my $body = $entity->bodyhandle;
-
- if ( $enc ne $charset && $body) {
- my @lines = $body->as_lines or return;
-
- # {{{ Convert the body
- eval {
- $RT::Logger->debug("Converting '$charset' to '$enc' for ". $head->mime_type . " - ". $head->get('subject'));
-
- # NOTE:: see the comments at the end of the sub.
- Encode::_utf8_off( $lines[$_] ) foreach ( 0 .. $#lines );
- Encode::from_to( $lines[$_], $charset => $enc ) for ( 0 .. $#lines );
- };
-
- if ($@) {
- $RT::Logger->error( "Encoding error: " . $@ . " defaulting to ISO-8859-1 -> UTF-8" );
- eval {
- Encode::from_to( $lines[$_], 'iso-8859-1' => $enc ) foreach ( 0 .. $#lines );
- };
- if ($@) {
- $RT::Logger->crit( "Totally failed to convert to utf-8: " . $@ . " I give up" );
- }
- }
- # }}}
-
- my $new_body = MIME::Body::InCore->new( \@lines );
-
- # set up the new entity
- $head->mime_attr( "content-type" => 'text/plain' )
- unless ( $head->mime_attr("content-type") );
- $head->mime_attr( "content-type.charset" => $enc );
- $entity->bodyhandle($new_body);
- }
-}
-
-# NOTES: Why Encode::_utf8_off before Encode::from_to
-#
-# All the strings in RT are utf-8 now. Quotes from Encode POD:
-#
-# [$length =] from_to($octets, FROM_ENC, TO_ENC [, CHECK])
-# ... The data in $octets must be encoded as octets and not as
-# characters in Perl's internal format. ...
-#
-# Not turning off the UTF-8 flag in the string will prevent the string
-# from conversion.
-
-# }}}
-
-# {{{ DecodeMIMEWordsToUTF8
-
-=head2 DecodeMIMEWordsToUTF8 $raw
-
-An utility method which mimics MIME::Words::decode_mimewords, but only
-limited functionality. This function returns an utf-8 string.
-
-It returns the decoded string, or the original string if it's not
-encoded. Since the subroutine converts specified string into utf-8
-charset, it should not alter a subject written in English.
-
-Why not use MIME::Words directly? Because it fails in RT when I
-tried. Maybe it's ok now.
-
-=cut
-
-sub DecodeMIMEWordsToUTF8 {
- my $str = shift;
- DecodeMIMEWordsToEncoding($str, 'utf-8');
-}
-
-sub DecodeMIMEWordsToEncoding {
- my $str = shift;
- my $enc = shift;
-
-
- @_ = $str =~ m/([^=]*)=\?([^?]+)\?([QqBb])\?([^?]+)\?=([^=]*)/g;
-
- return ($str) unless (@_);
-
- $str = "";
- while (@_) {
- my ($prefix, $charset, $encoding, $enc_str, $trailing) =
- (shift, shift, shift, shift, shift);
-
- $trailing =~ s/\s?\t?$//; # Observed from Outlook Express
-
- if ($encoding eq 'Q' or $encoding eq 'q') {
- use MIME::QuotedPrint;
- $enc_str =~ tr/_/ /; # Observed from Outlook Express
- $enc_str = decode_qp($enc_str);
- } elsif ($encoding eq 'B' or $encoding eq 'b') {
- use MIME::Base64;
- $enc_str = decode_base64($enc_str);
- } else {
- $RT::Logger->warning("RT::I18N::DecodeMIMEWordsToCharset got a " .
- "strange encoding: $encoding.");
- }
-
- # now we have got a decoded subject, try to convert into the encoding
- unless ($charset eq $enc) {
- eval { Encode::from_to($enc_str, $charset, $enc) };
- if ($@) {
- $charset = _GuessCharset( $enc_str );
- Encode::from_to($enc_str, $charset, $enc);
- }
- }
-
- $str .= $prefix . $enc_str . $trailing;
- }
-
- return ($str)
-}
-
-# }}}
-
-# {{{ _FindOrGuessCharset
-
-=head2 _FindOrGuessCharset MIME::Entity, $head_only
-
-When handed a MIME::Entity will first attempt to read what charset the message is encoded in. Failing that, will use Encode::Guess to try to figure it out
-
-If $head_only is true, only guesses charset for head parts. This is because header's encoding (e.g. filename="...") may be different from that of body's.
-
-=cut
-
-sub _FindOrGuessCharset {
- my $entity = shift;
- my $head_only = shift;
- my $head = $entity->head;
-
- if ($head->mime_attr("content-type.charset")) {
- return $head->mime_attr("content-type.charset");
- }
-
- if ( !$head_only and $head->mime_type =~ m{^text/}) {
- my $body = $entity->bodyhandle or return;
- return _GuessCharset( $body->as_string );
- }
- else {
- # potentially binary data -- don't guess the body
- return _GuessCharset( $head->as_string );
- }
-}
-
-# }}}
-
-
-# {{{ _GuessCharset
-
-=head2 _GuessCharset STRING
-
-use Encode::Guess to try to figure it out the string's encoding.
-
-=cut
-
-sub _GuessCharset {
- my $fallback = 'iso-8859-1';
- my $charset;
-
- if ( @RT::EmailInputEncodings and eval { require Encode::Guess; 1 } ) {
- Encode::Guess->set_suspects(@RT::EmailInputEncodings);
- my $decoder = Encode::Guess->guess( $_[0] );
-
- if ( ref $decoder ) {
- $charset = $decoder->name;
- $RT::Logger->debug("Guessed encoding: $charset");
- return $charset;
- }
- elsif ($decoder =~ /(\S+ or .+)/) {
- my %matched = map { $_ => 1 } split(/ or /, $1);
- return 'utf-8' if $matched{'utf8'}; # one and only normalization
-
- foreach my $suspect (@RT::EmailInputEncodings) {
- next unless $matched{$suspect};
- $RT::Logger->debug("Encode::Guess ambiguous ($decoder); using $suspect");
- $charset = $suspect;
- last;
- }
- }
- else {
- $RT::Logger->warning("Encode::Guess failed: $decoder; fallback to $fallback");
- }
- }
- else {
- $RT::Logger->warning("Cannot Encode::Guess; fallback to $fallback");
- }
-
- return($charset || $fallback);
-}
-
-# }}}
-
-# {{{ SetMIMEHeadToEncoding
-
-=head2 SetMIMEHeadToEncoding HEAD OLD_CHARSET NEW_CHARSET
-
-Converts a MIME Head from one encoding to another. This totally violates the RFC.
-We should never need this. But, Surprise!, MUAs are badly broken and do this kind of stuff
-all the time
-
-
-=cut
-
-sub SetMIMEHeadToEncoding {
- my ( $head, $charset, $enc, $preserve_words ) = ( shift, shift, shift, shift );
-
- $charset = 'utf-8' if $charset eq 'utf8';
- $enc = 'utf-8' if $enc eq 'utf8';
-
- return if $charset eq $enc and $preserve_words;
-
- foreach my $tag ( $head->tags ) {
- my @values = $head->get_all($tag);
- $head->delete($tag);
- foreach my $value (@values) {
- if ( $charset ne $enc ) {
-
- eval {
- Encode::_utf8_off($value);
- Encode::from_to( $value, $charset => $enc );
- };
- if ($@) {
- $RT::Logger->error( "Encoding error: " . $@
- . " defaulting to ISO-8859-1 -> UTF-8" );
- eval { Encode::from_to( $value, 'iso-8859-1' => $enc ) };
- if ($@) {
- $RT::Logger->crit( "Totally failed to convert to utf-8: " . $@ . " I give up" );
- }
- }
- }
- $value = DecodeMIMEWordsToEncoding( $value, $enc ) unless $preserve_words;
- $head->add( $tag, $value );
- }
- }
-
-}
-# }}}
-
-eval "require RT::I18N_Vendor";
-die $@ if ($@ && $@ !~ qr{^Can't locate RT/I18N_Vendor.pm});
-eval "require RT::I18N_Local";
-die $@ if ($@ && $@ !~ qr{^Can't locate RT/I18N_Local.pm});
-
-1; # End of module.
-