source: trunk/LATMOS-Accounts-Web/lib/I18N/AcceptLanguage.pm @ 2361

Last change on this file since 2361 was 2237, checked in by nanardon, 5 years ago

Move po files to make them availlable, handling Accept-Language

File size: 21.9 KB
Line 
1# $Id: AcceptLanguage.pm,v 1.8 2004/05/14 21:40:03 cgilmore Exp $
2#
3# Author          : Christian Gilmore
4# Created On      : Wed Sep 25 17:10:19 CDT 2002
5#
6# PURPOSE
7#     Matches language preference to available languages.
8#
9###############################################################################
10#
11# IBM Public License Version 1.0
12#
13# THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS IBM
14# PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR
15# DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF
16# THIS AGREEMENT.
17#
18# 1. DEFINITIONS
19#
20# "Contribution" means:
21#
22#   a) in the case of International Business Machines Corporation
23#   ("IBM"), the Original Program, and
24#
25#   b) in the case of each Contributor,
26#
27#   i) changes to the Program, and
28#
29#   ii) additions to the Program;
30#
31#   where such changes and/or additions to the Program originate from
32#   and are distributed by that particular Contributor. A Contribution
33#   'originates' from a Contributor if it was added to the Program by
34#   such Contributor itself or anyone acting on such Contributor's
35#   behalf. Contributions do not include additions to the Program
36#   which: (i) are separate modules of software distributed in
37#   conjunction with the Program under their own license agreement,
38#   and (ii) are not derivative works of the Program.
39#
40# "Contributor" means IBM and any other entity that distributes the
41# Program.
42#
43# "Licensed Patents " mean patent claims licensable by a Contributor
44# which are necessarily infringed by the use or sale of its
45# Contribution alone or when combined with the Program.
46#
47# "Original Program" means the original version of the software
48# accompanying this Agreement as released by IBM, including source
49# code, object code and documentation, if any.
50#
51# "Program" means the Original Program and Contributions.
52#
53# "Recipient" means anyone who receives the Program under this
54# Agreement, including all Contributors.
55#
56# 2. GRANT OF RIGHTS
57#
58#   a) Subject to the terms of this Agreement, each Contributor hereby
59#   grants Recipient a non-exclusive, worldwide, royalty-free
60#   copyright license to reproduce, prepare derivative works of,
61#   publicly display, publicly perform, distribute and sublicense the
62#   Contribution of such Contributor, if any, and such derivative
63#   works, in source code and object code form.
64#
65#   b) Subject to the terms of this Agreement, each Contributor hereby
66#   grants Recipient a non-exclusive, worldwide, royalty-free patent
67#   license under Licensed Patents to make, use, sell, offer to sell,
68#   import and otherwise transfer the Contribution of such
69#   Contributor, if any, in source code and object code form. This
70#   patent license shall apply to the combination of the Contribution
71#   and the Program if, at the time the Contribution is added by the
72#   Contributor, such addition of the Contribution causes such
73#   combination to be covered by the Licensed Patents. The patent
74#   license shall not apply to any other combinations which include
75#   the Contribution. No hardware per se is licensed hereunder.
76#
77#   c) Recipient understands that although each Contributor grants the
78#   licenses to its Contributions set forth herein, no assurances are
79#   provided by any Contributor that the Program does not infringe the
80#   patent or other intellectual property rights of any other entity.
81#   Each Contributor disclaims any liability to Recipient for claims
82#   brought by any other entity based on infringement of intellectual
83#   property rights or otherwise. As a condition to exercising the
84#   rights and licenses granted hereunder, each Recipient hereby
85#   assumes sole responsibility to secure any other intellectual
86#   property rights needed, if any. For example, if a third party
87#   patent license is required to allow Recipient to distribute the
88#   Program, it is Recipient's responsibility to acquire that license
89#   before distributing the Program.
90#
91#   d) Each Contributor represents that to its knowledge it has
92#   sufficient copyright rights in its Contribution, if any, to grant
93#   the copyright license set forth in this Agreement.
94#
95# 3. REQUIREMENTS
96#
97# A Contributor may choose to distribute the Program in object code
98# form under its own license agreement, provided that:
99#
100#   a) it complies with the terms and conditions of this Agreement;
101#
102# and
103#
104#   b) its license agreement:
105#
106#   i) effectively disclaims on behalf of all Contributors all
107#   warranties and conditions, express and implied, including
108#   warranties or conditions of title and non-infringement, and
109#   implied warranties or conditions of merchantability and fitness
110#   for a particular purpose;
111#
112#   ii) effectively excludes on behalf of all Contributors all
113#   liability for damages, including direct, indirect, special,
114#   incidental and consequential damages, such as lost profits;
115#   iii) states that any provisions which differ from this Agreement
116#   are offered by that Contributor alone and not by any other party;
117#   and
118#
119#   iv) states that source code for the Program is available from such
120#   Contributor, and informs licensees how to obtain it in a
121#   reasonable manner on or through a medium customarily used for
122#   software exchange.
123#
124# When the Program is made available in source code form:
125#
126#   a) it must be made available under this Agreement; and
127#
128#   b) a copy of this Agreement must be included with each copy of the
129#   Program.
130#
131# Each Contributor must include the following in a conspicuous
132# location in the Program:
133#
134#   Copyright © {date here}, International Business Machines
135#   Corporation and others. All Rights Reserved.
136#
137# In addition, each Contributor must identify itself as the originator
138# of its Contribution, if any, in a manner that reasonably allows
139# subsequent Recipients to identify the originator of the
140# Contribution.
141#
142# 4. COMMERCIAL DISTRIBUTION
143#
144# Commercial distributors of software may accept certain
145# responsibilities with respect to end users, business partners and
146# the like. While this license is intended to facilitate the
147# commercial use of the Program, the Contributor who includes the
148# Program in a commercial product offering should do so in a manner
149# which does not create potential liability for other Contributors.
150# Therefore, if a Contributor includes the Program in a commercial
151# product offering, such Contributor ("Commercial Contributor") hereby
152# agrees to defend and indemnify every other Contributor ("Indemnified
153# Contributor") against any losses, damages and costs (collectively
154# "Losses") arising from claims, lawsuits and other legal actions
155# brought by a third party against the Indemnified Contributor to the
156# extent caused by the acts or omissions of such Commercial
157# Contributor in connection with its distribution of the Program in a
158# commercial product offering. The obligations in this section do not
159# apply to any claims or Losses relating to any actual or alleged
160# intellectual property infringement. In order to qualify, an
161# Indemnified Contributor must: a) promptly notify the Commercial
162# Contributor in writing of such claim, and b) allow the Commercial
163# Contributor to control, and cooperate with the Commercial
164# Contributor in, the defense and any related settlement negotiations.
165# The Indemnified Contributor may participate in any such claim at its
166# own expense.
167#
168# For example, a Contributor might include the Program in a commercial
169# product offering, Product X. That Contributor is then a Commercial
170# Contributor. If that Commercial Contributor then makes performance
171# claims, or offers warranties related to Product X, those performance
172# claims and warranties are such Commercial Contributor's
173# responsibility alone. Under this section, the Commercial Contributor
174# would have to defend claims against the other Contributors related
175# to those performance claims and warranties, and if a court requires
176# any other Contributor to pay any damages as a result, the Commercial
177# Contributor must pay those damages.
178#
179# 5. NO WARRANTY
180#
181# EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
182# PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
183# ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,
184# ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
185# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient
186# is solely responsible for determining the appropriateness of using
187# and distributing the Program and assumes all risks associated with
188# its exercise of rights under this Agreement, including but not
189# limited to the risks and costs of program errors, compliance with
190# applicable laws, damage to or loss of data, programs or equipment,
191# and unavailability or interruption of operations.
192#
193# 6. DISCLAIMER OF LIABILITY
194#
195# EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
196# NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT,
197# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
198# (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON
199# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
200# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
201# THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
202# GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
203# DAMAGES.
204#
205# 7. GENERAL
206#
207# If any provision of this Agreement is invalid or unenforceable under
208# applicable law, it shall not affect the validity or enforceability
209# of the remainder of the terms of this Agreement, and without further
210# action by the parties hereto, such provision shall be reformed to
211# the minimum extent necessary to make such provision valid and
212# enforceable.
213#
214# If Recipient institutes patent litigation against a Contributor with
215# respect to a patent applicable to software (including a cross-claim
216# or counterclaim in a lawsuit), then any patent licenses granted by
217# that Contributor to such Recipient under this Agreement shall
218# terminate as of the date such litigation is filed. In addition, If
219# Recipient institutes patent litigation against any entity (including
220# a cross-claim or counterclaim in a lawsuit) alleging that the
221# Program itself (excluding combinations of the Program with other
222# software or hardware) infringes such Recipient's patent(s), then
223# such Recipient's rights granted under Section 2(b) shall terminate
224# as of the date such litigation is filed.
225#
226# All Recipient's rights under this Agreement shall terminate if it
227# fails to comply with any of the material terms or conditions of this
228# Agreement and does not cure such failure in a reasonable period of
229# time after becoming aware of such noncompliance. If all Recipient's
230# rights under this Agreement terminate, Recipient agrees to cease use
231# and distribution of the Program as soon as reasonably practicable.
232# However, Recipient's obligations under this Agreement and any
233# licenses granted by Recipient relating to the Program shall continue
234# and survive.
235#
236# IBM may publish new versions (including revisions) of this Agreement
237# from time to time. Each new version of the Agreement will be given a
238# distinguishing version number. The Program (including Contributions)
239# may always be distributed subject to the version of the Agreement
240# under which it was received. In addition, after a new version of the
241# Agreement is published, Contributor may elect to distribute the
242# Program (including its Contributions) under the new version. No one
243# other than IBM has the right to modify this Agreement. Except as
244# expressly stated in Sections 2(a) and 2(b) above, Recipient receives
245# no rights or licenses to the intellectual property of any
246# Contributor under this Agreement, whether expressly, by implication,
247# estoppel or otherwise. All rights in the Program not expressly
248# granted under this Agreement are reserved.
249#
250# This Agreement is governed by the laws of the State of New York and
251# the intellectual property laws of the United States of America. No
252# party to this Agreement will bring a legal action under this
253# Agreement more than one year after the cause of action arose. Each
254# party waives its rights to a jury trial in any resulting litigation.
255#
256###############################################################################
257
258
259# Package name
260package I18N::AcceptLanguage;
261
262
263# Required packages
264use 5.006001;
265use strict;
266use warnings;
267use vars qw($VERSION);
268
269
270# Global variables
271$VERSION = '1.04';
272
273
274###############################################################################
275###############################################################################
276# new: class object initialization
277###############################################################################
278###############################################################################
279sub new {
280  my $self = shift;
281  my $type = ref($self) || $self;
282  my $obj = bless {}, $type;
283  my %arg = @_;
284
285  $obj->debug($arg{debug} || 0);
286  $obj->defaultLanguage($arg{defaultLanguage} || '');
287  defined $arg{strict} ? $obj->strict($arg{strict}) : $obj->strict(1);
288
289  return $obj;
290}
291
292###############################################################################
293###############################################################################
294# debug: get/set method for debug messages
295###############################################################################
296###############################################################################
297sub debug {
298  my $acceptor = shift;
299
300  $acceptor->{debug} = shift if @_;
301  return $acceptor->{debug};
302}
303
304###############################################################################
305###############################################################################
306# defaultLanguage: get/set method for the server default language
307###############################################################################
308###############################################################################
309sub defaultLanguage {
310  my $acceptor = shift;
311
312  $acceptor->{defaultLanguage} = shift if @_;
313  return $acceptor->{defaultLanguage};
314}
315
316###############################################################################
317###############################################################################
318# strict: get/set method for strict protocol conformance
319###############################################################################
320###############################################################################
321sub strict {
322  my $acceptor = shift;
323
324  $acceptor->{strict} = shift if @_;
325  return $acceptor->{strict};
326}
327
328###############################################################################
329###############################################################################
330# accepts: determines what the highest priority commonly known language
331#   between client and server is.
332###############################################################################
333###############################################################################
334sub accepts {
335  my ($acceptor, $clientPreferences, $supportedLanguages) = @_;
336
337  # Basic sanity check
338  if (not $clientPreferences or ref($supportedLanguages) ne 'ARRAY') {
339    return $acceptor->defaultLanguage();
340  }
341
342  # There should be no whitespace anways, but a cleanliness/sanity check
343  $clientPreferences =~ s/\s//g;
344  print "Client preferences are $clientPreferences\n" if $acceptor->debug();
345
346  # Prepare the list of client-acceptable languages
347  my @languages = ();
348  foreach my $tag (split(/,/, $clientPreferences)) {
349    my ($language, $quality) = split(/\;/, $tag);
350    $quality =~ s/^q=//i if $quality;
351    $quality = 1 unless $quality;
352    next if $quality <= 0;
353    # We want to force the wildcard to be last
354    $quality = 0 if ($language eq '*');
355    # Pushing lowercase language here saves processing later
356    push(@languages, { quality => $quality,
357                       language => $language,
358                       lclanguage => lc($language) });
359  }
360
361  # Prepare the list of server-supported languages
362  my %supportedLanguages = ();
363  my %secondaryLanguages = ();
364  foreach my $language (@$supportedLanguages) {
365    print "Added language $language (lower-cased) to supported hash\n"
366      if $acceptor->debug();
367    $supportedLanguages{lc($language)} = $language;
368    if ($language =~ /^([^-]+)-?/) {
369      print "Added language $1 (lower-cased) to secondary hash\n"
370        if $acceptor->debug();
371      $secondaryLanguages{lc($1)} = $language;
372    }
373  }
374
375  # Reverse sort the list, making best quality at the front of the array
376  @languages = sort { $b->{quality} <=> $a->{quality} } @languages;
377
378  my $secondaryMatch = '';
379  foreach my $tag (@languages) {
380    print "Matching ", $tag->{lclanguage}, "\n" if $acceptor->debug();
381    if (exists($supportedLanguages{$tag->{lclanguage}})) {
382      # Client en-us eq server en-us
383      print "Returning language ", $supportedLanguages{$tag->{language}}, "\n"
384        if $acceptor->debug();
385      return $supportedLanguages{$tag->{language}}
386        if exists($supportedLanguages{$tag->{language}});
387      return $supportedLanguages{$tag->{lclanguage}};
388    } elsif (exists($secondaryLanguages{$tag->{lclanguage}})) {
389      # Client en eq server en-us
390      print "Returning language ", $secondaryLanguages{$tag->{language}}, "\n"
391        if $acceptor->debug();
392      return $secondaryLanguages{$tag->{language}}
393        if exists($secondaryLanguages{$tag->{language}});
394      return $supportedLanguages{$tag->{lclanguage}};
395    } elsif (!($acceptor->strict()) &&
396             $tag->{lclanguage} =~ /^([^-]+)-/ &&
397             exists($secondaryLanguages{$1}) &&
398             $secondaryMatch eq '') {
399      # Client en-gb eq server en-us
400      print "Setting supported secondaryMatch of $1 for ", $tag->{lclanguage}, "\n"
401        if $acceptor->debug();
402      $secondaryMatch = $secondaryLanguages{$1};
403    } elsif ($tag->{lclanguage} =~ /^([^-]+)-/ &&
404             exists($secondaryLanguages{$1}) &&
405             $secondaryMatch eq '') {
406      # Client en-us eq server en
407      print "Setting secondary secondaryMatch of $1 for ", $tag->{lclanguage}, "\n"
408        if $acceptor->debug();
409      $secondaryMatch = $supportedLanguages{$1};
410    } elsif ($tag->{lclanguage} eq '*') {
411      # * matches every language not already specified.
412      # It doesn't care which we pick, so let's pick the default,
413      # if available, then the first in the array.
414      print "Setting default for *\n" if $acceptor->debug();
415      return $acceptor->defaultLanguage() if $acceptor->defaultLanguage();
416      return $supportedLanguages->[0];
417    }
418  }
419
420  # No primary matches. Secondary? (ie, en-us requested and en supported)
421  print "Testing for secondaryMatch\n" if $acceptor->debug();
422  return $secondaryMatch if $secondaryMatch;
423
424  # No matches. Let's return the default, if set.
425  print "Returning default, if any\n" if $acceptor->debug();
426  return $acceptor->defaultLanguage();
427}
428
4291;
430
431__END__
432
433###############################################################################
434###############################################################################
435# Documentation - try 'pod2text AcceptLanguage.pm'
436###############################################################################
437###############################################################################
438
439=head1 NAME
440
441I18N::AcceptLanguage - Matches language preference to available
442languages
443
444=head1 SYNOPSIS
445
446  use I18N::AcceptLanguage;
447
448  my $supportedLanguages = [( 'en-us', 'fr' )];
449
450  my $acceptor = I18N::AcceptLanguage->new();
451  my $language = $acceptor->accepts($ENV{HTTP_ACCEPT_LANGUAGE},
452                                    $supportedLanguages);
453
454=head1 DESCRIPTION
455
456B<I18N::AcceptLanguage> matches language preference to available
457languages per rules defined in RFC 2616, section 14.4: HTTP/1.1 -
458Header Field Definitions - Accept-Language.
459
460=head1 PUBLIC METHODS
461
462=over 2
463
464=item accepts( CLIENT_PREFERENCES, SUPPORTED_LANGUAGES )
465
466Returns the highest priority common language between client and
467server. If no common language is found, the defaultLanguage is
468returned. If defaultLanuage is also not set, an empty string is
469returned. The method expects two arguments:
470
471=over 2
472
473=item CLIENT_PREFERENCES
474
475A string in the same format defined in RFC 2616, quoted here:
476
477  1#( ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" ) [ "'" "q" "=" qvalue ] )
478
479Examples:
480
481  da, en-gb;q=0.8, en;q=0.7
482
483  en-us, ja, *
484
485=item SUPPORTED_LANGUAGES
486
487A reference to a list of language ranges supported by the server.
488
489=back
490
491=item new( [ OPTIONS ] )
492
493Returns a new I18N::AcceptLanguage object. The method accepts the
494following key/value pair options:
495
496=over 2
497
498=item debug
499
500A boolean set to either 0 or 1. When set to 1, debug messages will be
501printed to STDOUT. The value of debug defaults to 0.
502
503=item defaultLanguage
504
505A string representing the server's default language choice. The value
506of defaultLanguage defaults to an empty string.
507
508=item strict
509
510A boolean set to either 0 or 1. When set to 1, the software strictly
511conforms to the protocol specification. When set to 0, the software
512will perform a secondary, aggressive language match regardless of
513country (ie, a client asking for only en-gb will get back en-us if the
514server does not accept en-gb or en but does accept en-us). The last
515matching language in the supported languages list will be chosen. The
516value of strict defaults to 1.
517
518=back
519
520=back
521
522=head1 PRIVATE METHODS
523
524=over 2
525
526=item debug( [ BOOLEAN ] )
527
528A get/set method that returns the value of debug, set by the optional
529method argument.
530
531=item defaultLanguage( [ LANGUAGE ] )
532
533A get/set method that returns the value of defaultLanguage, set by the
534optional method argument.
535
536=item strict( [ BOOLEAN ] )
537
538A get/set method that returns the value of strict, set by the optional
539method argument.
540
541=back
542
543=head1 NOTES
544
545=over 2
546
547=item Case Sensitivity
548
549Language matches are done in a case-insensitive manner but results are
550case-sensitive to the value found in the SUPPORTED_LANGUAGES list.
551
552=back
553
554=head1 AVAILABILITY
555
556This module is available on CPAN worldwide and requires perl version
5575.6.1 or higher be installed.
558
559=head1 AUTHORS
560
561Christian Gilmore <cag@us.ibm.com>
562
563=head1 SEE ALSO
564
565RFC 2616
566
567=head1 COPYRIGHT
568
569Copyright (C) 2003, 2004 International Business Machines Corporation
570and others. All Rights Reserved.
571
572This module is free software; you can redistribute it and/or
573modify it under the terms of the IBM Public License.
574
575=cut
Note: See TracBrowser for help on using the repository browser.