Description: Help files for dealing with language/locale settings.
Author: Gunnar Hjalmarsson <ubuntu@gunnar.cc>

---
 configure.ac                            |    1 
 data/Makefile.am                        |    1 
 data/langtools/Makefile.am              |   17 ++++++
 data/langtools/del-profile-env-settings |   13 +++++
 data/langtools/language-options         |   66 +++++++++++++++++++++++++++
 data/langtools/language-validate        |   78 ++++++++++++++++++++++++++++++++
 data/langtools/language2locale          |   65 ++++++++++++++++++++++++++
 data/langtools/main-countries           |   28 +++++++++++
 data/langtools/save-to-pam-env          |   36 ++++++++++++++
 data/langtools/set-language-helper      |   25 ++++++++++
 data/langtools/update-langlist          |   48 +++++++++++++++++++
 11 files changed, 378 insertions(+)

--- accountsservice.orig/configure.ac
+++ accountsservice/configure.ac
@@ -218,6 +218,7 @@ AC_CONFIG_FILES([
 Makefile
 po/Makefile.in
 data/Makefile
+data/langtools/Makefile
 src/Makefile
 src/libaccountsservice/Makefile
 src/libaccountsservice/accountsservice.pc
--- /dev/null
+++ accountsservice/data/langtools/del-profile-env-settings
@@ -0,0 +1,13 @@
+#!/bin/sh -e
+
+homedir=$1
+
+test -n "$homedir" || exit 1
+
+test -f "$homedir/.profile" && {
+    cd "$homedir"
+    for var in 'LANGUAGE' 'LANG' 'LC_MESSAGES' 'LC_CTYPE' 'LC_COLLATE'; do
+        sed -i "/^export $var=\"[^[:space:]]*\"$/d" .profile
+    done
+}
+
--- /dev/null
+++ accountsservice/data/langtools/language2locale
@@ -0,0 +1,65 @@
+#!/bin/sh -e
+#
+# - takes the first choice language in the LANGUAGE priority list as argument
+# - outputs locale name corresponding to that language
+
+lang=$1
+locale_name=
+
+test -n "$lang" || exit 1
+
+langtoolsdir=/usr/share/language-tools
+
+langcode=${lang%%[_@]*}
+locales=
+for loc in $( locale -a | grep -F .utf8 ); do
+    # skip locales for other languages
+    if [ $langcode = ${loc%%[._@]*} ]; then
+        loc=${loc%.*}${loc#*.utf8}
+        locales="$locales $loc"
+    fi
+done
+
+# exact match
+for loc in $locales; do
+    if [ $lang = $loc ]; then
+        locale_name=$( echo $loc | sed -r 's/([^@]+)/\1.UTF-8/' )
+        break
+    fi
+done
+
+if [ -z "$locale_name" -a $lang = ${lang%_[A-Z]*} ]; then
+
+    # try the "main" country code if any
+    main_country=
+    while read line; do
+        if [ "${line%%[[:space:]]*}" = $langcode ]; then
+            main_country=${line##*[[:space:]]}
+            if [ $lang != ${lang#*@} ]; then
+                main_country=$main_country@${lang#*@}
+            fi
+            break
+        fi
+    done < $langtoolsdir/main-countries
+    if [ -n "$main_country" ]; then
+        for loc in $locales; do
+            if [ $main_country = $loc ]; then
+                locale_name=$( echo $loc | sed -r 's/([^@]+)/\1.UTF-8/' )
+                break
+            fi
+        done
+    fi
+
+    # try out fitting locale with any country code
+    if [ -z "$locale_name" -a $langcode != 'zh' ]; then
+        for loc in $locales; do
+            if [ "${loc%%[_@]*}" = $langcode ]; then
+                locale_name=$( echo $loc | sed -r 's/([^@]+)/\1.UTF-8/' )
+                break
+            fi
+        done
+    fi
+fi
+
+echo $locale_name
+
--- /dev/null
+++ accountsservice/data/langtools/language-options
@@ -0,0 +1,66 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+my $langtoolsdir = '/usr/share/language-tools';
+
+# get the locales available on the system
+my @avail_locales = map { chomp; s/\.utf8//; $_ } qx( locale -a | grep -F .utf8 );
+
+# add items without country code to facilitate lookups
+my %extended_localelist;
+for my $loc (@avail_locales) {
+    ( my $lang = $loc ) =~ s/_[A-Z]+//;
+    @extended_localelist{$loc, $lang} = (1, 1);
+}
+
+# get the union of /usr/share/locale-langpack and /usr/share/locale
+my %translation_dirs;
+for my $dir ('/usr/share/locale-langpack', '/usr/share/locale') {
+    if ( opendir my ($dh), $dir ) {
+        $translation_dirs{$_} = 1 for readdir $dh;
+    }
+}
+
+# get the intersection of available translation_dirs and the extended locale list
+my %intersection;
+for ( keys %extended_localelist ) {
+    $intersection{$_} = 1 if $translation_dirs{$_};
+}
+
+# adjustments
+if ( open my $fh, '<', "$langtoolsdir/main-countries" ) {
+    # If country code items in a language exist:
+    # - Remove the item without country code, since gettext won't find a
+    #   translation under e.g. 'de_DE' if the first item in LANGUAGE is 'de'
+    #   (see https://launchpad.net/bugs/700213). 'en' is kept, though, since
+    #   it's always the last item in LANGUAGE per design.
+    # - Make sure that the main dialect of the language is represented among
+    #   the country code items (see https://launchpad.net/bugs/710148).
+    my %main;
+    while ( <$fh> ) {
+        next if /^\s*(?:#|$)/;
+        my ($k, $v) = split;
+        $main{$k} = $v;
+    }
+    my %count;
+    for ( keys %intersection ) {
+        next if /^en[^a-z]/;
+        ( my $not_country = $_ ) =~ s/_[A-Z]+//;
+        $count{$not_country} ++;
+    }
+    for my $langcode ( keys %count ) {
+        if ( $count{$langcode} > 1 ) {
+            delete $intersection{$langcode};
+            $intersection{ $main{$langcode} } = 1 if $main{$langcode};
+        }
+    }
+} else {
+    # not access to the language-to-main-dialect map
+    # => stick with a minimum of list manipulation
+    delete $intersection{'zh'};
+}
+
+# print the resulting list of language options
+print join("\n", sort keys %intersection) || 'en';
+
--- /dev/null
+++ accountsservice/data/langtools/language-validate
@@ -0,0 +1,78 @@
+#!/bin/sh -e
+
+lang=$1
+validated_language=
+
+test -n "$lang" || exit 1
+
+langtoolsdir=/usr/share/language-tools
+
+#
+# discard possible fallback languages
+#
+lang=${lang%%:*}
+
+#
+# remove possible encoding part
+#
+if [ $lang != ${lang%.utf8*} ]; then
+    lang=${lang%.*}${lang#*.utf8}
+elif [ $lang != ${lang%.UTF-8*} ]; then
+    lang=${lang%.*}${lang#*.UTF-8}
+fi
+
+#
+# make sure that the output is a valid language option
+#
+options=$( $langtoolsdir/language-options )
+
+# exact match
+for opt in $options; do
+    if [ $opt = $lang ]; then
+        validated_language=$lang
+        break
+    fi
+done
+
+if [ -z "$validated_language" ]; then
+    langcode=${lang%%[_@]*}
+
+    # try the "main" country code if any
+    main_country=
+    while read line; do
+        if [ "${line%%[[:space:]]*}" = $langcode ]; then
+            main_country=${line##*[[:space:]]}
+            if [ $lang != ${lang#*@} ]; then
+                main_country=$main_country@${lang#*@}
+                is_variant=true
+            fi
+            break
+        fi
+    done < $langtoolsdir/main-countries
+    if [ -n "$main_country" ]; then
+        for opt in $options; do
+            if [ $main_country = $opt ]; then
+                validated_language=$main_country
+                break
+            fi
+        done
+    fi
+
+    # try out fitting language option without paying regard to
+    # country code or variant
+    if [ -z "$validated_language" ]; then
+        for opt in $options; do
+            if [ "${opt%%[_@]*}" = $langcode -a $langcode != 'zh' ]; then
+                validated_language=$opt
+                break
+            fi
+        done
+    fi
+fi
+
+if [ -z "$validated_language" ]; then
+    validated_language='en'
+fi
+
+echo $validated_language
+
--- /dev/null
+++ accountsservice/data/langtools/main-countries
@@ -0,0 +1,28 @@
+# If multiple country codes are present among the available locales for
+# a language, we may want to map the language code to the language's
+# main or origin country. The list below aims to serve that purpose.
+#
+aa	aa_ET
+ar	ar_EG
+bn	bn_BD
+ca	ca_ES
+de	de_DE
+el	el_GR
+en	en_US
+es	es_ES
+eu	eu_ES
+fr	fr_FR
+fy	fy_NL
+it	it_IT
+li	li_NL
+nl	nl_NL
+om	om_ET
+pa	pa_PK
+pt	pt_PT
+ru	ru_RU
+so	so_SO
+sr	sr_RS
+sv	sv_SE
+ti	ti_ER
+tr	tr_TR
+
--- /dev/null
+++ accountsservice/data/langtools/Makefile.am
@@ -0,0 +1,17 @@
+langtoolsdir = ${datadir}/language-tools
+
+install-data-hook:
+	if test '!' -d $(DESTDIR)$(langtoolsdir); then \
+		$(mkinstalldirs) $(DESTDIR)$(langtoolsdir); \
+		chmod 755 $(DESTDIR)$(langtoolsdir); \
+	fi
+
+	$(INSTALL_SCRIPT)  del-profile-env-settings  $(DESTDIR)$(langtoolsdir)/del-profile-env-settings
+	$(INSTALL_SCRIPT)  language-options          $(DESTDIR)$(langtoolsdir)/language-options
+	$(INSTALL_SCRIPT)  language-validate         $(DESTDIR)$(langtoolsdir)/language-validate
+	$(INSTALL_SCRIPT)  language2locale           $(DESTDIR)$(langtoolsdir)/language2locale
+	$(INSTALL_DATA)    main-countries            $(DESTDIR)$(langtoolsdir)/main-countries
+	$(INSTALL_SCRIPT)  save-to-pam-env           $(DESTDIR)$(langtoolsdir)/save-to-pam-env
+	$(INSTALL_SCRIPT)  set-language-helper       $(DESTDIR)$(langtoolsdir)/set-language-helper
+	$(INSTALL_SCRIPT)  update-langlist           $(DESTDIR)$(langtoolsdir)/update-langlist
+
--- /dev/null
+++ accountsservice/data/langtools/save-to-pam-env
@@ -0,0 +1,36 @@
+#!/bin/sh -e
+#
+# updates the ~/.pam_environment config file
+
+homedir=$1
+locale_name=$2
+language_list=$3
+
+[ -n "$homedir" -a -n "$locale_name" ] || exit 1
+
+# create ~/.pam_environment if it doesn't exist
+touch "$homedir/.pam_environment" || exit 1
+
+save_to_pam_env() {
+    var=$1; value=$2
+    if [ "$( grep "^$var=" .pam_environment )" ]; then
+        sed -r -i "s/^($var=).*/\1$value/" .pam_environment
+    else
+        echo "$var=$value" >> .pam_environment
+    fi
+}
+
+cd "$homedir"
+if [ -n "$language_list" ]; then
+    save_to_pam_env 'LANGUAGE' $language_list
+    save_to_pam_env 'LANG' $locale_name
+else
+    for var in 'LC_NUMERIC' 'LC_TIME' 'LC_MONETARY' 'LC_PAPER' 'LC_NAME' \
+               'LC_ADDRESS' 'LC_TELEPHONE' 'LC_MEASUREMENT'; do
+        save_to_pam_env $var $locale_name
+    done
+    echo $locale_name
+fi
+
+exit 0
+
--- /dev/null
+++ accountsservice/data/langtools/set-language-helper
@@ -0,0 +1,25 @@
+#!/bin/sh -e
+
+homedir=$1
+language=$2
+validated_language=
+
+[ -n "$language" -a -n "$homedir" ] || exit 1
+
+langtoolsdir=/usr/share/language-tools
+
+validated_language=$( $langtoolsdir/language-validate $language )
+
+if [ $language = "${language%:*}" ]; then
+    renewed_langlist=$( $langtoolsdir/update-langlist $validated_language "$homedir" )
+else
+    # $language contains a priority list
+    renewed_langlist=$validated_language:${language#*:}
+fi
+
+locale_name=$( $langtoolsdir/language2locale $validated_language )
+
+( $langtoolsdir/save-to-pam-env "$homedir" $locale_name $renewed_langlist ) || exit 1
+
+echo $validated_language
+
--- /dev/null
+++ accountsservice/data/langtools/update-langlist
@@ -0,0 +1,48 @@
+#!/bin/sh -e
+#
+# update-langlist maintains the LANGUAGE priority list. It does so in
+# a simplified manner, unlike the principal UI for setting the user
+# language which provides full control.
+
+first_language=$1
+homedir=$2
+renewed_langlist=
+
+[ -n "$first_language" -a -n "$homedir" ] || exit 1
+
+get_old_langlist() {
+    if [ -r "$homedir/.pam_environment" ]; then
+        while read line; do
+            if [ "${line%=*}" = 'LANGUAGE' ]; then
+                old_langlist=${line#*=}
+                break
+            fi
+        done < $homedir/.pam_environment
+    fi
+}
+
+old_langlist=
+english=true
+if [ ${first_language%%[_@]*} != 'en' ]; then
+    get_old_langlist
+    english=false
+fi
+
+if [ -n "$old_langlist" ] && ! $english; then
+    if expr $old_langlist : ".*:$first_language:" > /dev/null ; then
+        renewed_langlist=$( echo $old_langlist | sed -r "s/(.+:)($first_language:)/\2\1/" )
+    elif [ ${old_langlist%%:*} = $first_language ]; then
+        # no change
+        renewed_langlist=$old_langlist
+    else
+        renewed_langlist=$first_language:$old_langlist
+    fi
+else
+    # build fresh list with 'en' as the last element
+    # no other languages needed if English was selected
+    renewed_langlist=$first_language
+    [ $first_language != 'en' ] && renewed_langlist=$renewed_langlist:en
+fi
+
+echo $renewed_langlist
+
--- accountsservice.orig/data/Makefile.am
+++ accountsservice/data/Makefile.am
@@ -1,3 +1,4 @@
+SUBDIRS = langtools
 
 dbusifdir   = $(datadir)/dbus-1/interfaces
 dbusif_DATA = \
