Skip to content

Commit

Permalink
Issue #205: Add support for translated country names
Browse files Browse the repository at this point in the history
Also show the flag in the country selection.
Load language packs for the most popular languages
  • Loading branch information
bschmalhofer committed Dec 1, 2023
1 parent 822f24f commit ab56d5f
Show file tree
Hide file tree
Showing 6 changed files with 244 additions and 45 deletions.
7 changes: 7 additions & 0 deletions Kernel/Config/Files/XML/Framework.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3098,6 +3098,13 @@ You can log in via the following URL:
</Hash>
</Value>
</Setting>
<Setting Name="ReferenceData::TranslatedCountryNames" Required="0" Valid="0">
<Description Translatable="1">Translate the country names in the country selection. The CLDR country codes will be stored. Needs Locale::CLDR and the relevant language packs.</Description>
<Navigation>Core::ReferenceData</Navigation>
<Value>
<Item ValueType="Checkbox">0</Item>
</Value>
</Setting>
<Setting Name="PerformanceLog" Required="0" Valid="1" ConfigLevel="200">
<Description Translatable="1">Enables performance log (to log the page response time). It will affect the system performance. Frontend::Module###AdminPerformanceLog must be enabled.</Description>
<Navigation>Core::PerformanceLog</Navigation>
Expand Down
38 changes: 22 additions & 16 deletions Kernel/Modules/AdminCustomerCompany.pm
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

package Kernel::Modules::AdminCustomerCompany;

use v5.24;
use strict;
use warnings;
use namespace::autoclean;

# core modules
use List::Util qw(any);
Expand Down Expand Up @@ -554,6 +556,7 @@ sub _Edit {
my ( $Self, %Param ) = @_;

my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');

$LayoutObject->Block(
Name => 'Overview',
Expand All @@ -571,9 +574,6 @@ sub _Edit {
Data => \%Param,
);

# get config object
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');

# send parameter ReadOnly to JS object
$LayoutObject->AddJSData(
Key => 'ReadOnly',
Expand Down Expand Up @@ -661,16 +661,24 @@ sub _Edit {
);

}
elsif ( $Entry->[0] =~ /^CustomerCompanyCountry/i ) {
my $OptionRequired = '';
if ( $Entry->[4] ) {
$OptionRequired = 'Validate_Required';
}

# build Country string
my $CountryList = $Kernel::OM->Get('Kernel::System::ReferenceData')->CountryList();
elsif ( $Entry->[0] =~ m/^CustomerCompanyCountry/i ) {

# build Country selection with English names
$Block = 'Option';
my $OptionRequired = $Entry->[4] ? 'Validate_Required' : '';
my $CountryList;
if ( $ConfigObject->Get('ReferenceData::TranslatedCountryNames') ) {

# Flag+Name => code
$CountryList = $Kernel::OM->Get('Kernel::System::ReferenceData')->TranslatedCountryList(
Language => $LayoutObject->{UserLanguage},
);
}
else {

# English name => English name
$CountryList = $Kernel::OM->Get('Kernel::System::ReferenceData')->CountryList;
}
$Param{Option} = $LayoutObject->BuildSelection(
Data => $CountryList,
PossibleNone => 1,
Expand All @@ -681,14 +689,11 @@ sub _Edit {
SelectedID => defined( $Param{ $Entry->[0] } ) ? $Param{ $Entry->[0] } : 1,
);
}
elsif ( $Entry->[0] =~ /^ValidID/i ) {
my $OptionRequired = '';
if ( $Entry->[4] ) {
$OptionRequired = 'Validate_Required';
}
elsif ( $Entry->[0] =~ m/^ValidID/i ) {

# build ValidID string
$Block = 'Option';
my $OptionRequired = $Entry->[4] ? 'Validate_Required' : '';
$Param{Option} = $LayoutObject->BuildSelection(
Data => { $ValidObject->ValidList(), },
Name => $Entry->[0],
Expand Down Expand Up @@ -754,6 +759,7 @@ sub _Edit {
}
}
}

return 1;
}

Expand Down
126 changes: 97 additions & 29 deletions Kernel/System/ReferenceData.pm
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package Kernel::System::ReferenceData;
use v5.24;
use strict;
use warnings;
use namespace::autoclean;
use utf8;

# core modules

Expand All @@ -27,19 +29,44 @@ use Locale::Country qw(all_country_names);

# OTOBO modules

our @ObjectDependencies = (
'Kernel::Config',
'Kernel::System::Log',
our @ObjectDependencies = qw(
Kernel::Config
Kernel::System::Log
Kernel::System::Main
);

=for stopwords da CLDR
=head1 NAME
Kernel::System::ReferenceData - ReferenceData lib
=head1 DESCRIPTION
Contains reference data. For now, this is limited to just a list of ISO country
codes.
Contains reference data. For now, this is limited to:
=over 4
=item ISO 3166-1 country codes and English names
Currently there are 249 officially assigned codes.
Retired codes are not included.
=item Translated country names from the Unicode CLDR
The keys are two letter country codes. The codes are made up of:
=over 4
=item the 249 officially assigned ISO 3166-1 codes
=item exceptional reservations: Ascension Island, Clipperton Island, Diego Garcia, Ceuta and Melilla, Canary Islands, and Tristan da Cunha
=item user-assigned temporary country code: Kosovo
=back
=back
=head1 PUBLIC INTERFACE
Expand All @@ -55,44 +82,41 @@ sub new {
my ( $Type, %Param ) = @_;

# allocate new hash for object
my $Self = {};
bless( $Self, $Type );

return $Self;
return bless {}, $Type;
}

=head2 CountryList()
return a list of countries as a hash reference. The countries are based on ISO
3166-2 and are provided by the Perl module Locale::Code::Country, or optionally
3166-1 and are provided by the Perl module Locale::Code::Country, or optionally
from the SysConfig setting ReferenceData::OwnCountryList.
my $CountryList = $ReferenceDataObject->CountryList(
Result => 'CODE', # optional: returns CODE => Country pairs conform ISO 3166-2.
my $CountryName2Name = $ReferenceDataObject->CountryList()
or
my $CountryName2Code = $ReferenceDataObject->CountryList()
Result => 'CODE', # optional: returns CODE => Country pairs conform ISO 3166-1 alpha-2.
);
=cut

sub CountryList {
my ( $Self, %Param ) = @_;

if ( !defined $Param{Result} || $Param{Result} ne 'CODE' ) {
$Param{Result} = undef;
}

my $Countries = $Kernel::OM->Get('Kernel::Config')->Get('ReferenceData::OwnCountryList');
# Determine whether the values of the result should be the codes
my $ReturnCodes = ( $Param{Result} // '' ) eq 'CODE';

if ( $Param{Result} && $Countries ) {
my $OwnCountries = $Kernel::OM->Get('Kernel::Config')->Get('ReferenceData::OwnCountryList');
if ($OwnCountries) {

# return Code => Country pairs from SysConfig
return $Countries;
}
elsif ($Countries) {
return $OwnCountries if $ReturnCodes;

# return Country => Country pairs from SysConfig
my %CountryJustNames = map { $_ => $_ } values %$Countries;
my %CountryName2Name = map { $_ => $_ } values $OwnCountries->%*;

return \%CountryJustNames;
return \%CountryName2Name;
}

# get the country list from Locale::Country
Expand All @@ -105,21 +129,65 @@ sub CountryList {
);
}

if ( $Param{Result} ) {
if ($ReturnCodes) {

# return Code => Country pairs from ISO list
my %Countries;
my %CountryName2Code;
for my $Country (@CountryNames) {
$Countries{$Country} = country2code( $Country, 1 );
$CountryName2Code{$Country} = country2code( $Country, 1 );
}

return \%Countries;
return \%CountryName2Code;
}

# return Country => Country pairs from ISO list
my %CountryNames = map { $_ => $_ } @CountryNames;
my %CountryName2Name = map { $_ => $_ } @CountryNames;

return \%CountryName2Name;
}

=head2 TranslatedCountryList()
returns a mapping of translated country names to two letter country codes.
The translated country name are prepended by their flag.
The data is provided by L<Locale::CLDR>.
my $CountryName2Code = $ReferenceDataObject->TranslatedCountryList(
Language => 'de',
);
=cut

sub TranslatedCountryList {
my ( $Self, %Param ) = @_;

my $MainObject = $Kernel::OM->Get('Kernel::System::Main');

# Locale::CLDR is not required for OTOBO
return {} unless $MainObject->Require('Locale::CLDR');

# TODO: Check whether $Param{Language} is supported

# For getting the country flags.
# See https://en.wikipedia.org/wiki/Regional_indicator_symbol
# This indicators are in a sequence: ord(🇩) = ord('🇦') - ord('A') + ord('D')
my $Base = ord('🇦') - ord('A');
my %Letter2Indicator = map
{ $_ => chr( $Base + ord($_) ) }
( 'A' .. 'Z' );

my $Locale = Locale::CLDR->new( language_id => $Param{Language} );
my $AllRegions = $Locale->all_regions(); # includes regions like '001' => World
my %Code2Name;
for my $Code ( grep { length $_ == 2 } keys $AllRegions->%* ) {
my $Flag =
join '',
map { $Letter2Indicator{$_} }
split //, $Code;
$Code2Name{$Code} = "$AllRegions->{$Code} $Flag";
}

return \%CountryNames;
return \%Code2Name;
}

1;
19 changes: 19 additions & 0 deletions bin/otobo.CheckModules.pl
Original file line number Diff line number Diff line change
Expand Up @@ -1202,6 +1202,25 @@ =head1 DESCRIPTION
},
);

# Add CLDR language packs. It is not decided yet whether all 50 languages are added.
# So let's first go for the languages that have a translation quote of more than 80%.
# See https://translate.otobo.org/projects/otobo10/otobo/.
for my $Code (qw(De Nb Es Zh Pt Ar Hu Sr Ko Ru)) {
push @NeededModules,
{
Module => "Locale::CLDR::Locales::$Code",
Features => ['div:cldr'],
VersionRequired => '0.34.3',
Comment => 'localisation from the CLDR project',
InstTypes => {
aptget => undef, # not in any Debian package
emerge => undef,
zypper => undef,
ports => undef,
},
};
}

# Sanity check.
for my $Module (@NeededModules) {
die 'Module must be set!' unless defined $Module->{Module};
Expand Down
Loading

0 comments on commit ab56d5f

Please sign in to comment.