ACC SHELL

Path : /proc/self/root/usr/share/YaST2/modules/
File Upload :
Current File : //proc/self/root/usr/share/YaST2/modules/Language.ycp

/**
 * File:	modules/Language.ycp
 * Module:	Language
 * Summary:	This module does all language related stuff:
 * Authors:	Klaus Kaempf <kkaempf@suse.de>
 *		Thomas Roelz <tom@suse.de>
 * Maintainer:  Jiri Suchomel <jsuchome@suse.cz>
 *
 * $Id: Language.ycp 60270 2010-01-07 14:09:34Z jsuchome $
 */

{

module "Language";
textdomain "country";


import "AsciiFile";
import "Directory";
import "Encoding";
import "FileUtils";
import "InstExtensionImage";
import "Linuxrc";
import "Misc";
import "Mode";
import "PackageCallbacks";
import "PackageSystem";
import "Popup";
import "ProductFeatures";
import "SlideShow";
import "Stage";


/**
 * currently selected language
 */
global string language = "en_US";

/**
 * original language
 */
global string language_on_entry = "en_US";

/**
 * language preselected in /etc/install.inf
 */
global string preselected	= "en_US";

/**
 * user readable description of language
 */
string name = "English (US)";

boolean linuxrc_language_set = false;

/**
 * Default language to be restored with MakeProposal.
 */
string default_language = "en_US";


/**
 * Default settings for ROOT_USES_LANG in /etc/sysconfig/language
 */
string rootlang = "ctype";


/**
 * Default settings for INSTALLED_LANGUAGES in /etc/sysconfig/language
 */
global string languages		= "";

/**
 * Original value of INSTALLED_LANGUAGES
 */
global string languages_on_entry	= "";

/**
 * Use utf8 in locale
 */
boolean use_utf8 = true;

/**
 * ncurses mode
 */
boolean text_mode	= nil;

global boolean ExpertSettingsChanged = false;

/**
 * Was the initial language selection skipped? (see bug 223258)
 * (It can be, if the language was selected in linuxrc)
 */
global boolean selection_skipped	= false;

/**
 * level of translation completeness
 */
map<string,integer> translation_status	= $[];

// map (locale: 1) of available locales
map<string,integer> locales	= $[];

// map with all languages (cached - needs to be reread for retranslation)
map<string, list> languages_map = $[];

// mapping of language to its default (proposed) time zone
map<string,string> lang2timezone	= $[];

// mapping of language to its default (proposed) kbd layout
map<string,string> lang2keyboard	= $[];

// directory with languages descriptions
string languages_directory	= nil;

// languages that cannot be correctly shown in text mode
list cjk_languages	= [
    "ja", "ko", "zh", "hi", "km", "pa", "bn", "gu", "mr", "si", "ta", "vi"

];

// FATE #302955: Split translations out of installation system
// [ "en_US", "en_GB", "de", "cs" ]
global list <string> available_lang_filenames = nil;


/**
 * Check if the language is "CJK"
 * (and thus could not be shown in text mode - see bug #102958)
 */
global define boolean CJKLanguage (string lang) {

    string l = substring (lang, 0, 2);
    return contains (cjk_languages, l);
}

/**
 * return the value of text_mode (true for ncurses)
 */
global define boolean GetTextMode () {

    if (text_mode== nil)
    {
	map display_info	= UI::GetDisplayInfo ();
	text_mode		= display_info["TextMode"]:false;
    }
    return text_mode;
}

/**
 * Read language DB: translatable strings will be translated to current language
 */
define void read_languages_map() {

    if (languages_directory == nil)
    {
	languages_directory	= Directory::datadir + "/languages";
    }
    foreach (string file,
	(list<string>) SCR::Read (.target.dir, languages_directory, []),
    {
	if (!regexpmatch (file, "language_.+\\.ycp$"))
	    return;
	map language_map = (map)
	    eval (SCR::Read (.target.yast2, "languages/" + file));
	if (language_map == nil) language_map = $[];
	string code	= file;
	foreach (string key, any val, (map<string,any>) language_map, {
	    if (is (val, list))
	    {
		languages_map[key]	= (list) val;
		code			= key;
	    }
	});
	if (!haskey (lang2timezone, code))
	    lang2timezone[code]	= language_map["timezone"]:"US/Eastern";
	if (!haskey (lang2keyboard, code))
	    lang2keyboard[code]	= language_map["keyboard"]:"en_US";
    });

    if (languages_map == nil) languages_map = $[];
}

/**
 * Read only the map of one language
 * @param language code
 */
define map ReadLanguageMap (string lang) {

    map ret	= $[];

    if (languages_directory == nil)
    {
	languages_directory	= Directory::datadir + "/languages";
    }
    string file	= sformat ("language_%1.ycp", lang);
    if (FileUtils::Exists (languages_directory + "/" + file))
    {
	ret	= (map) eval (SCR::Read (.target.yast2, "languages/" + file));
	if (ret == nil)
	    ret	= $[];
    }
    return ret;
}

/**
 * Return the whole map with language descriptions
 * @param force force new loading of the map from the files (forces the change
 * of translations to current language)
 */
global map<string, list> GetLanguagesMap (boolean force) {

    if (size (languages_map) == 0 || force)
	read_languages_map();
    return languages_map;
}

// list of items for secondary languages term
list<term> secondary_items	= [];

map english_names	= $[];

/**
 * Return English translation of given language (Fate 301789)
 */
string EnglishName (string code, string backup) {

    if (english_names[code]:"" == "")
    {
	if (language == "en_US")
	    english_names[code]	= backup;
	else
	    y2warning ("nothing in english_names...");
    }
    return english_names[code]:backup;
}

/**
 * Fill the map with English names of languages
 */
void FillEnglishNames (string lang) {

    if (lang == "en_US")
	return; // will be filled in on first start
    if (use_utf8)
	WFM::SetLanguage ("en_US", "UTF-8");
    else
	WFM::SetLanguage ("en_US");
    foreach (string code, list info, GetLanguagesMap (true),
    {
	english_names[code]	= info[4]:"";
    });
    if (use_utf8)
	WFM::SetLanguage (lang, "UTF-8");
    else
	WFM::SetLanguage (lang);
}


/**
 * return the content of lang2timezone map
 * (mapping of languages to their default (proposed) time zones)
 */
global define map<string,string> GetLang2TimezoneMap (boolean force) {
    if (size (languages_map) == 0 && force)
	read_languages_map();
    return lang2timezone;
}

/**
 * return the content of lang2keyboard map
 * (mapping of languages to their default (proposed) keyboard layouts)
 */
global define map<string,string> GetLang2KeyboardMap (boolean force) {
    if (size (languages_map) == 0 && force)
	read_languages_map();
    return lang2keyboard;
}

/**
 * return the map of all supported countries and language codes
 */
global define map<string,integer> GetLocales () {

    if (locales == nil || locales == $[])
    {
	map out = (map)SCR::Execute (.target.bash_output, "/usr/bin/locale -a");
	foreach (string l, splitstring (out["stdout"]:"", "\n"), {
	    integer pos = findfirstof (l, ".@");

	    if (pos != nil && pos >= 0)
		l = substring (l, 0, pos);

	    locales [l]	= 1;
	});
    }

    return locales;
}

/**
 * For given language, return the file name of language extension (image)
 * to be downloaded to the inst-sys
 * (FATE #302955: Split translations out of installation system)
 */
string GetLanguageExtensionFilename (string language) {

    if (available_lang_filenames == nil) {
	map<string,integer> lang_numbers	= $[];
	foreach (string code, list data, GetLanguagesMap (false), {
	    string short	= splitstring (code, "_")[0]:"";
	    if (lang_numbers[short]:0 == 0)
		lang_numbers[short]	= 1;
	    else
		lang_numbers[short]	= lang_numbers[short]:0 + 1;
	});
	available_lang_filenames = maplist (string code, list data,
	    GetLanguagesMap (false), {
	    string short	= splitstring (code, "_")[0]:"";
	    if (lang_numbers[short]:0 > 1)
		return code;
	    else
		return short;
	});
    }

    list <string> check_for_languages = [language];

    // 'en_US' ? add also 'en'
    if (size (language) > 2) {
	check_for_languages = add (check_for_languages, splitstring (language, "_")[0]:"");
    }

    // Default fallback
    string filename = "yast2-trans-en_US.rpm";

    foreach (string one_language, check_for_languages, {
	if (contains (available_lang_filenames, one_language)) {
	    filename = sformat ("yast2-trans-%1.rpm", one_language);
	    break;
	}
    });
    // yast2-trans-pt.rpm doesn't fit into the algorithm above, see bnc#386298
    if (language == "pt_PT")
	return "yast2-trans-pt.rpm";

    y2milestone ("Using %1 for %2", filename, language);
    return filename;
}


/**
 * Set module to selected language.
 * @param lang language string ISO code of language
 */
global define void Set (string lang) {

    y2milestone ("original language: %1; setting to lang:%2", language, lang);

    if (language != lang)	// Do it only if different
    {
	if (Stage::initial () && !Mode::test () && !Mode::live_installation ())
	{
	    y2milestone ("integrating translation extension...");
	    // busy message
	    Popup::ShowFeedback ("",_("Downloading installation system language extension..."));
	    InstExtensionImage::DownloadAndIntegrateExtension (GetLanguageExtensionFilename (lang));
	    Popup::ClearFeedback ();
	    y2milestone ("integrating translation extension... done");
	}
	if (size (languages_map) == 0)
	    read_languages_map();

	if (size (locales) == 0)
	    GetLocales ();

	if (locales[lang]:0 != 1 && size(lang) > 0)
	{
	    lang = substring (lang, 0, 2);
	    boolean found = false;
	    foreach (string k, list dummy, languages_map,
	    {
		if (!found && substring (k, 0, 2) ==lang)
		{
		    found = true;
		    lang = k;
		}
	    });
	}
	name		= languages_map[lang, 0]:lang;
	if (Mode::config ())
	    name	= languages_map[lang, 4]:lang;
	language	= lang;
	Encoding::SetEncLang (language);
    }

    if (Stage::initial () && !Mode::test ())
    {
	map yinf = $[];
	AsciiFile::SetDelimiter (yinf, " ");
	AsciiFile::ReadFile (yinf, "/etc/yast.inf");
	list lines = AsciiFile::FindLineField (yinf, 0, "Language:");
	if (size(lines) > 0)
	{
	    AsciiFile::ChangeLineField (yinf, lines[0]:-1, 1, language);
	}
	else
	{
	    AsciiFile::AppendLine (yinf, ["Language:", language] );
	}
	AsciiFile::RewriteFile (yinf, "/etc/yast.inf");

	// update "name" for proposal when it cannot be shown correctly
	if (GetTextMode () && CJKLanguage (lang) && !CJKLanguage (preselected))
	{
	    name	= languages_map[lang, 1]:lang;
	}
    }
}


/**
 * Set the language that was read from sysconfig,
 * read only one needed language file
 */
global define void QuickSet (string lang) {

    y2milestone ("original language: %1; setting to lang:%2", language, lang);

    if (language != lang)
    {
	map lang_map	= ReadLanguageMap (lang);
	name		= lang_map[lang, 0]:lang;
	language	= lang;
	Encoding::SetEncLang (language);
    }
}

global define boolean LinuxrcLangSet() {

    return linuxrc_language_set;
}

/**
 * generate the whole locale string for given language according to DB
 * (e.g. de_DE -> de_DE.UTF-8)
 */
global define string GetLocaleString (string lang) {

    if (size (languages_map) == 0)
	read_languages_map();

    list language_info = languages_map[lang]:[];
    if (!haskey (languages_map, lang))
	language_info	= [ lang, lang, ".UTF-8" ];

    // full language code
    string val = language;
    if( use_utf8 )
	val = val + language_info[2]:"";
    else
	val = val + language_info[3]:"";

    y2milestone( "locale %1", val );
    return val;
}


/**
 * Store current language as default language.
 */
global define void SetDefault() {
    y2milestone("Setting default language: %1", language);
    default_language = language;
    return;
}

/**
 * Read the RC_LANG value from sysconfig and exctract language from it
 * @return language
 */
global define string ReadSysconfigLanguage () {

    string local_lang = Misc::SysconfigRead (.sysconfig.language.RC_LANG, language);

    integer pos = findfirstof (local_lang, ".@");

    if (pos != nil && pos >= 0)
    {
	local_lang = substring (local_lang, 0, pos);
    }

    y2milestone ("language from sysconfig: %1", local_lang);
    return local_lang;
}

/**
 * Read the rest of language values from sysconfig
 */
global define void ReadSysconfigValues () {

    rootlang = Misc::SysconfigRead (.sysconfig.language.ROOT_USES_LANG, rootlang);
    // during live installation, we have sysconfig.language.RC_LANG available
    if (!Stage::initial () || Mode::live_installation ())
    {
	string val = toupper (Misc::SysconfigRead (.sysconfig.language.RC_LANG, ""));
	use_utf8 = search (val, ".UTF-8") != nil;
    }
    else
    {
	use_utf8 = true;
    }
    languages = Misc::SysconfigRead (.sysconfig.language.INSTALLED_LANGUAGES, "");
}

/**
 * Constructor
 *
 * Initializes module either from /etc/install.inf
 * or from /etc/sysconfig/language
 */
global define void Language() {

    if (Mode::config ())
    {
	// read the translated name: bug #180633
	read_languages_map();
	name	= languages_map[language, 4]:language;
	return;
    }

    if (Stage::initial () && !Mode::live_installation ())
    {
	string lang = (string)SCR::Read (.content.LANGUAGE);
	y2milestone ("content LANGUAGE %1", lang);

	preselected = Linuxrc::InstallInf ("Locale");
	y2milestone ("install_inf Locale %1", preselected);
	if (preselected != nil && preselected != "")
	{
	    lang = preselected;
	    if (lang != "en_US")
	    {
		linuxrc_language_set = true;
	    }
	}
	else
	    preselected	= "en_US";

	if (lang == nil)
	    lang = "";
	y2milestone ("lang after checking /etc/install.inf: %1", lang );
	if (lang == "")
	{
	    lang = Pkg::GetTextLocale();
	    y2milestone ("setting lang to default language: %1", lang);
	}
        // Ignore any previous settings and take language from control file.
	string l = ProductFeatures::GetStringFeature ("globals","language");
        if (l != nil && l != "")
        {
            lang = l;
	    y2milestone ("setting lang to ProductFeatures::language: %1", lang);
        }
	FillEnglishNames (lang);
	Set (lang);		// coming from /etc/install.inf
	SetDefault ();		// also default
    }
    else
    {
	string local_lang = ReadSysconfigLanguage ();
	QuickSet (local_lang);
	SetDefault();		// also default
	if (Mode::live_installation () || Stage::firstboot ())
	{
	    FillEnglishNames (local_lang);
	}
    }
    if (SCR::Read (.target.size, "/etc/sysconfig/language") > 0)
    {
	ReadSysconfigValues ();
    }
    Encoding::SetUtf8Lang (use_utf8);
}

/**
 * Store the inital values; in normal mode, read from system was done in constructor
 * @param really: also read the values from the system
 */
global define boolean Read (boolean really) {

    if (really)
    {
	Set (ReadSysconfigLanguage ());
	ReadSysconfigValues ();
    }

    language_on_entry	= language;
    languages_on_entry	= languages;

    y2milestone ("language: %1, languages: %2", language_on_entry, languages_on_entry);

    ExpertSettingsChanged	= false;

    return true;
}

/**
 * was anything modified?
 */
global define boolean Modified () {

    return (language != language_on_entry			||
	    ExpertSettingsChanged				||
	    sort (splitstring (languages, ",")) !=
	    sort (splitstring (languages_on_entry, ","))
    );
}

/**
 * Does the modification of language(s) require installation of new packages?
 * This test compares the list of original languages (primary+secondary) with
 * the list after user's modifications
 */
global define boolean PackagesModified () {

    return
	sort (union(splitstring(languages, ","), [language])) !=
	sort (union(splitstring(languages_on_entry, ","), [language_on_entry]));
}

/**
 * GetExpertValues()
 *
 * Return the values for the various expert settings in a map
 *
 * @param       -
 *
 * @return  map with values filled in
 *
 */
global define map GetExpertValues () {

    return $[
	"rootlang"		: rootlang,
        "use_utf8"		: use_utf8,
    ];
}

/**
 * SetExpertValues()
 *
 * Set the values of the various expert setting
 *
 * @param       val     map with new values of expert settings
 *
 * @return  void
 *
 */
global define void SetExpertValues (map val) {

    if (haskey (val,"rootlang") && size (val["rootlang"]:"") >0)
    {
        rootlang = val["rootlang"]:"";
    }
    if (haskey (val,"use_utf8"))
    {
        use_utf8 = val["use_utf8"]:false;
	Encoding::SetUtf8Lang (use_utf8);
    }
}

/**
 * WfmSetLanguag()
 *
 * Set the given language in WFM and UI
 *
 * @param       language (could be different from current in CJK case)
 *
 * @return      -
 */
global define void WfmSetGivenLanguage (string lang) {

    if (Mode::config ())
	return;

    string encoding	= (use_utf8) ? "UTF-8" : Encoding::console;

    y2milestone ( "language %1 enc %2 utf8:%3", lang, encoding, use_utf8 );

    UI::SetLanguage (lang, encoding);

    if (use_utf8)
    {
	WFM::SetLanguage(lang, "UTF-8");
    }
    else
    {
	WFM::SetLanguage(lang);
    }
}


/**
 * WfmSetLanguag()
 *
 * Set the current language in WFM and UI
 *
 * @param       -
 *
 * @return      -
 */
global define void WfmSetLanguage () {

    WfmSetGivenLanguage (language);
}


/**
 * Return proposal string.
 *
 * @return	string	user readable description.
 *		If force_reset is true reset the module to the language
 *		stored in default_language.
 */
global define list<string> MakeProposal (boolean force_reset,boolean language_changed)
{
    y2milestone("force_reset: %1", force_reset);
    y2milestone("language_changed: %1", language_changed);

    if (force_reset)
    {
	Set (default_language);	// reset
    }
    list<string> ret =  [
	// summary label
	sformat (_("Primary Language: %1"), name)
    ];
    if (size (languages_map) == 0 || language_changed)
    {
	read_languages_map();
    }
    // maybe additional languages were selected in package selector (bnc#393007)
    list<string> langs		= splitstring (languages, ",");
    list<string> missing	= [];
    foreach (string additional, Pkg::GetAdditionalLocales (), {
	// add the language for both kind of values ("cs" vs. "pt_PT")
	if (!contains (langs, additional))
	{
	    if (additional == "en")
		additional	= "en_US";
	    if (additional == "pt")
		additional	= "pt_PT";
	    if (haskey (languages_map, additional))
	    {
		missing	= add (missing, additional);
		return;
	    }
	    if (contains (langs, additional)) //en_US or pt_PT already installed
		return;
	    // now, let's hope there's only one full entry for the short one
	    // (e.g. cs_CZ for cs)
	    foreach (string k, list dummy, languages_map,
	    {
		if (substring (k, 0, 2) == additional)
		{
		    missing = add (missing, k);
		    break;
		}
	    });
	}
    });
    if (size (missing) > 0)
    {
	langs		= (list<string>) union (langs, missing);
	languages	= mergestring (langs,",");
    }
    // now, generate the summary strings
    if (languages != "" && languages != language)
    {
	langs	= [];
	foreach (string lang, splitstring (languages, ","), {
	    if (lang != language)
	    {
		string l = languages_map[lang,4]:languages_map[lang,0]:"";
		if (l != "")
		    langs = add (langs, l);
	    }
	});
	if (size (langs) > 0)
	{
	    // summary label
	    ret = add (ret, sformat (_("Additional Languages: %1"),
		mergestring (langs,", ")));
	}
    }
    return ret;
}

/**
 * Return 'simple' proposal string.
 * @return string preformated description.
 */
global define string MakeSimpleProposal ()
{
    import "HTML";

    list<string> ret =  [
	// summary label
	sformat (_("Primary Language: %1"), name)
    ];
    if (languages != "" && languages != language)
    {
	list<string> langs	= [];
	foreach (string lang, splitstring (languages, ","), {
	    if (lang != language)
	    {
		string l = languages_map[lang,4]:languages_map[lang,0]:"";
		if (l != "")
		    langs = add (langs, l);
	    }
	});
	if (size (langs) > 0)
	{
	    // summary label
	    ret = add (ret, sformat (_("Additional Languages: %1"),
		HTML::List (langs)));
	}
    }
    return HTML::List (ret);
}

/**
 * return user readable description of language
 */
global define string GetName () {

    return name;
}

/**
 * Return a map of ids and names to build up a selection list
 * for the user. The key is used later in the Set function
 * to select this language. The name is a translated string.
 *
 * @return map of $[ language : [ utf8-name, ascii-name] ...]
 *			for all known languages
 *			'language' is the (2 or 5 char)  ISO language code.
 *			'utf8-name' is a user-readable (UTF-8 encoded !) string.
 *			'ascii-name' is an english (ascii encoded !) string.
 * @see Set
 */
global define map<string, list> Selection() {

    read_languages_map();

    return mapmap (string code, list data, languages_map,
	``($[code: [data[0]:"", data[1]:"", data[4]:data[0]:""]]));
}


/**
 * Save state to target.
 */
global define void Save() {

    string loc = GetLocaleString (language);

    SCR::Write (.sysconfig.language.RC_LANG, loc);

    if (find (loc, "zh_HK") == 0)
    {
	SCR::Write(.sysconfig.language.RC_LC_MESSAGES,"zh_TW"+substring(loc,5));
    }
    else
    {
	// FIXME ugly hack: see bug #47711
	string lc_mess = (string)SCR::Read(.sysconfig.language.RC_LC_MESSAGES);
	if (find (lc_mess, "zh_TW") == 0)
	{
	    SCR::Write (.sysconfig.language.RC_LC_MESSAGES, "");
	}
    }

    SCR::Write (.sysconfig.language.ROOT_USES_LANG, rootlang);
    SCR::Write (.sysconfig.language.INSTALLED_LANGUAGES, languages);
    SCR::Write (.sysconfig.language, nil);

    y2milestone ("Saved data for language: <%1>", loc);
}

/**
 * Initializes source and target,
 * computes the packages necessary to install and uninstall,
 * checks for disk space (#50745)
 * @return false when there is not enough disk space for new packages
 */
global define boolean PackagesInit (list<string> selected_languages) {

    PackageSystem::EnsureSourceInit ();
    PackageSystem::EnsureTargetInit ();

    Pkg::SetAdditionalLocales (selected_languages);
    Pkg::PkgSolve (true);

    boolean ok	= true;
    foreach (string mountpoint, list<integer> usage, Pkg::TargetGetDU (), {
	if (usage[2]:0 > usage[0]:0)
	{
	    ok = false;
	}
    });
    return ok;;
}

/**
 * Install and uninstall packages selected by Pkg::SetAdditionalLocales
 */
global boolean PackagesCommit () {

    if (!Mode::commandline ())
    {
/* work-around for following in order not to depend on yast2-packager
       PackageSlideShow::InitPkgData (false);
              "value" : PackageSlideShow::total_size_to_install / 1024 , // kilobytes
*/
        list<list<integer> > total_sizes_per_cd_per_src = Pkg::PkgMediaSizes();
	integer total_size_to_install = 0;
	foreach (integer item, flatten (total_sizes_per_cd_per_src), {
	    if (item != -1)
		total_size_to_install = total_size_to_install + item;
	});

	SlideShow::Setup([$[
              "name" : "packages",
              "description" : _("Installing Packages..."),
              "value" : total_size_to_install / 1024 , // kilobytes
              "units" : `kb,
        ]]);

	SlideShow::ShowTable();

	SlideShow::OpenDialog ();
	SlideShow::MoveToStage( "packages" );
    }
    Pkg::PkgCommit (0);
    if (!Mode::commandline ())
    {
	SlideShow::CloseDialog();
    }
    return true;
}

/**
 * de_DE@UTF-8 -> "DE"
 * @return country part of language
 */
global define string GetGivenLanguageCountry (string lang) {

    string country	= lang;

    if (country == nil || country == "")
        country = default_language;
    if (country != nil && country != "")
    {
        if (find (country, "@") != -1)
            country = splitstring (country, "@") [0]:"";
    }
    if (country != nil && country != "")
    {
        if (find (country, ".") != -1)
            country = splitstring (country, ".") [0]:"";
    }
    if (country != nil && country != "")
    {
        if (find(country, "_") != -1)
            country = splitstring (country, "_") [1]:"";
	else
	    country = toupper(country);
    }

    y2debug("country=%1",country);
    return country;
}


/**
 * de_DE@UTF-8 -> "DE"
 * @return country part of language
 */
global define string GetLanguageCountry() {

    return GetGivenLanguageCountry (language);
}


/**
 * Returns true if translation for given language is not complete
 */
global define boolean IncompleteTranslation (string lang) {

    if (!haskey (translation_status,lang))
    {
	string file	= "/usr/lib/YaST2/trans/" + lang + ".status";
	if (!FileUtils::Exists (file))
	{
	    string ll	= splitstring (lang, "_") [0]:"";
	    if (ll != "")
		file	= "/usr/lib/YaST2/trans/" + ll + ".status";
	}

	string status	= (string) SCR::Read (.target.string, file);

	if (status != nil && status != "")
	{
	    integer to_i		= tointeger (status);
	    translation_status[lang]	= (to_i != nil) ? to_i : 0;
	}
	else
	    translation_status[lang]	= 100;
    }
    integer treshold = tointeger (ProductFeatures::GetStringFeature (
	"globals", "incomplete_translation_treshold"));
    if (treshold == nil) treshold = 95;

    return translation_status[lang]:0 < treshold;
}

/**
 * Checks if translation is complete and displays
 * Continue/Cancel popup messsage if it is not
 * return true if translation is OK or user agrees with the warning
 */
global boolean CheckIncompleteTranslation (string lang) {
    if (IncompleteTranslation (language))
    {
	// continue/cancel message
	return Popup::ContinueCancel (_("Translation of the primary language is not complete.
Some texts may be displayed in English.
"));
    }
    return true;
}

/**
 * AutoYaST interface function: Get the Language configuration from a map.
 * @param settings imported map
 * @return success
 */
global define boolean Import (map settings) {

    if (languages_on_entry == "")
	Read (false); // only save original values

    Set (settings["language"]:language);
    languages	= settings["languages"]:languages;

    SetExpertValues (settings);

    list<string> llanguages = splitstring (languages, ",");
    if (!contains (llanguages, language))
    {
	llanguages	= add (llanguages, language);
	languages	= mergestring (llanguages, ",");
    }
    // set the language dependent packages to install
    if (Mode::autoinst ())
    {
	Pkg::SetPackageLocale (language);
	Pkg::SetAdditionalLocales (splitstring (languages, ","));
    }

    return true;
}

/**
 * AutoYaST interface function: Return the Language configuration as a map.
 * @return map with the settings
 */
global define map Export () {

    map ret = $[
	"language"	: language,
	"languages"	: languages
    ];
    if (rootlang != "ctype")
	ret["rootlang"]	= rootlang;
    if (!use_utf8)
	ret["use_utf8"]	= use_utf8;
    return ret;
}

/**
 * AutoYaST interface function: Return the summary of Language configuration as a map.
 * @return summary string
 */
global define string Summary () {

    return MakeSimpleProposal ();
}

// kind: `first_screen, `primary, `secondary
global list<term> GetLanguageItems (symbol kind) {

    list<term> ret	= [];

    // already generated in previous run with `primary
    if (kind == `secondary && secondary_items != [])
    {
	return secondary_items;
    }
    secondary_items	= [];

    boolean use_ascii	= GetTextMode ();

    map<string,list> en_name_sort =
	    mapmap (string code, list info, Selection(), {
		string english	= EnglishName (code, info[2]:code);
		return $[
		    english : [
			info[use_ascii ? 1 : 0]:"",
			code,
		    ]
		];
    });
    if (kind == `first_screen)
    {
	// fate 301789
	// English name of language (translated language).
	// e.g. German (Deutsch)
	ret	= maplist (string name, list codelist, en_name_sort, {
	    string label = substring (codelist[1]:"", 0, 2) == "en" ?
		codelist[0]:"" : sformat ("%1 - %2", name, codelist[0]:"");
	    return `item (`id (codelist[1]:""), label);
	});
	return ret;
    }
    // sort language by ASCII with help of a map
    // $[ "ascii-name" : [ "user-readable-string", "code" ], ...]
    // the "user-readable-string" is either ascii or utf8, depending
    // on textmode probed above (workaround because there isn't any
    // usable console font for all languages).

    map<string,list> languageselsort = mapmap (
	string lang_code, list lang_info, Selection(), {
	    string key	= lang_info [1]:lang_code;
	    return $[
		key		: [
		    lang_info[use_ascii ? 1 : 0]:"",
		    lang_code,
		    lang_info[2]:key
		]
	    ];
	}
    );

    // mapping of language name (translated) to language code
    map lang2code		= $[];
    // mapping language code to native form
    map code2native		= $[];
    // list of language names (translated)
    list<string> lang_list	= [];
    foreach (any name, list codelist, languageselsort, {
	lang2code [codelist[2]:""]	= codelist[1]:"";
	lang_list	= add (lang_list, codelist[2]:"");
	code2native[codelist[1]:""]	= codelist[0]:"";
    });


    if (Stage::firstboot ())
    {
	// show also native forms in firstboot (bnc#492812)
	ret	= maplist (string name, list codelist, en_name_sort, {
	    string code	= codelist[1]:"";
	    string label = substring (code, 0, 2) == "en" ?
		codelist[0]:"" : sformat ("%1 - %2", name, codelist[0]:"");
	    return `item (`id (code), label, language == code);
	});
	return ret;
    }
    boolean primary_included	= false;

    if (kind == `primary || kind == `secondary)
    {
	list<string>languages_l	= splitstring (languages, ",");
	// filter the primary language from the list of secondary ones:
        languages_l	= filter (string l, languages_l, ``(l != language));

	boolean	icons	= !(Stage::initial () || Stage::firstboot ());
	list<term> primary_items	= [];
	secondary_items = maplist (string trans_lang, lsort (lang_list),
	{
	    string code		= lang2code [trans_lang]:"";
	    string show_lang	= language == code ? trans_lang : sformat ("%1 - %2", trans_lang, code2native[code]:"");
	    primary_items	= add (primary_items, icons ?
		`item (`id (code), `icon(tolower(Language::GetGivenLanguageCountry(code))+"/flag.png"), show_lang, language == code) :
		`item (`id (code), trans_lang, language == code));
	    if (language == code)
		primary_included	= true;
	    return icons ?
		`item (`id (code), `icon(tolower(Language::GetGivenLanguageCountry(code))+"/flag.png"), trans_lang, contains (languages_l, code)) :
		`item (`id (code), trans_lang, contains (languages_l, code));
	});
	if (!primary_included)
	    primary_items = add (primary_items,
		`item (`id (language), language, true));
	ret = (kind == `primary) ?  primary_items : secondary_items;
    }
    return ret;
}

/**
 * check if selected language has support on media (F301238)
 * show a warning when not
 */
global void CheckLanguagesSupport (string selected_language) {

    string linguas = (string) SCR::Read (.content.LINGUAS);

    if (linguas == nil) {
	y2warning ("No LINGUAS tag defined in content file");
	return;
    }

    y2milestone ("content LINGUAS %1", linguas);
    list <string> all_linguas = splitstring (linguas, " ");
    string language_short = splitstring (selected_language, "_")[0]:"";

    if (!contains (all_linguas, selected_language) &&
	!contains (all_linguas, language_short))
    {
	y2milestone ("Language %1 is not fully supported", selected_language);
	    // popup message
	Popup::Message (_("Only minimal support for the selected language is included on this media.
Add the Language add-on CD as an additional repository in order to get the appropriate support
for this language.
"));
    }
}

/**
 * Set current YaST language to English if method for showing text in
 * current language is not supported (usually for CJK languages)
 * See http://bugzilla.novell.com/show_bug.cgi?id=479529 for discussion
 * @boolean show_popup if information popup about the change should be shown
 * @return true if UI language was changed
 */
global boolean SwitchToEnglishIfNeeded (boolean show_popup) {

    if (Stage::normal ())
    {
	y2milestone ("no language switching in normal stage");
	return false;
    }
    if (GetTextMode () &&
	// current language is CJK
	CJKLanguage (language) &&
	// fbiterm is not running
	getenv ("TERM") != "iterm")
    {
	if (show_popup)
	{
	    // popup message (user selected CJK language in text mode)
	    Popup::Message (_("The selected language cannot be used in text mode. English is used for
installation, but the selected language will be used for the new system."));
	}
	WfmSetGivenLanguage ("en_US");
	return true;
    }
    return false;
}




/* EOF */
}

ACC SHELL 2018