diff --git a/apps/Makefile b/apps/Makefile index a76386d21..e95a74369 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -55,6 +55,8 @@ $(call object_for,apps/apps_container_storage.cpp apps/apps_container.cpp apps/m # I18n file generation +country_preferences = apps/country_preferences.csv + # The header is refered to as so make sure it's findable this way SFLAGS += -I$(BUILD_DIR) @@ -71,7 +73,7 @@ $(eval $(call rule_for, \ I18N, \ apps/i18n.cpp, \ $(i18n_files), \ - $$(PYTHON) apps/i18n.py --codepoints $(code_points) --header $$(subst .cpp,.h,$$@) --implementation $$@ --locales $$(EPSILON_I18N) --countries $$(EPSILON_COUNTRIES) --files $$^ --generateISO6391locales $$(EPSILON_GETOPT), \ + $$(PYTHON) apps/i18n.py --codepoints $(code_points) --countrypreferences $(country_preferences) --header $$(subst .cpp,.h,$$@) --implementation $$@ --locales $$(EPSILON_I18N) --countries $$(EPSILON_COUNTRIES) --files $$^ --generateISO6391locales $$(EPSILON_GETOPT), \ global \ )) diff --git a/apps/country_preferences.csv b/apps/country_preferences.csv new file mode 100644 index 000000000..0e95a872b --- /dev/null +++ b/apps/country_preferences.csv @@ -0,0 +1,11 @@ +CountryCode,CountryPreferences::AvailableExamModes,CountryPreferences::MethodForQuartiles,Poincare::Preferences::UnitFormat +CA,StandardOnly,MedianOfSublist,Metric +DE,StandardOnly,MedianOfSublist,Metric +ES,StandardOnly,MedianOfSublist,Metric +FR,StandardOnly,CumulatedFrequency,Metric +GB,StandardOnly,MedianOfSublist,Metric +IT,StandardOnly,CumulatedFrequency,Metric +NL,All,MedianOfSublist,Metric +PT,StandardOnly,MedianOfSublist,Metric +US,StandardOnly,MedianOfSublist,Imperial +WW,StandardOnly,MedianOfSublist,Metric diff --git a/apps/country_preferences.h b/apps/country_preferences.h new file mode 100644 index 000000000..703801c97 --- /dev/null +++ b/apps/country_preferences.h @@ -0,0 +1,34 @@ +#ifndef COUNTRY_PREFERENCES_H +#define COUNTRY_PREFERENCES_H + +#include + +class CountryPreferences { +public: + enum class AvailableExamModes : uint8_t { + StandardOnly, + All + }; + + enum class MethodForQuartiles : uint8_t { + MedianOfSublist, + CumulatedFrequency + }; + + constexpr CountryPreferences(AvailableExamModes availableExamModes, MethodForQuartiles methodForQuartiles, Poincare::Preferences::UnitFormat unitFormat) : + m_availableExamModes(availableExamModes), + m_methodForQuartiles(methodForQuartiles), + m_unitFormat(unitFormat) + {} + + constexpr AvailableExamModes availableExamModes() const { return m_availableExamModes; } + constexpr MethodForQuartiles methodForQuartiles() const { return m_methodForQuartiles; } + constexpr Poincare::Preferences::UnitFormat unitFormat() const { return m_unitFormat; } + +private: + const AvailableExamModes m_availableExamModes; + const MethodForQuartiles m_methodForQuartiles; + const Poincare::Preferences::UnitFormat m_unitFormat; +}; + +#endif diff --git a/apps/exam_mode_configuration_official.cpp b/apps/exam_mode_configuration_official.cpp index 20c89b412..5cdc1fb8f 100644 --- a/apps/exam_mode_configuration_official.cpp +++ b/apps/exam_mode_configuration_official.cpp @@ -6,12 +6,12 @@ constexpr Shared::SettingsMessageTree ExamModeConfiguration::s_modelExamChildren[2] = {Shared::SettingsMessageTree(I18n::Message::ActivateExamMode), Shared::SettingsMessageTree(I18n::Message::ActivateDutchExamMode)}; int ExamModeConfiguration::numberOfAvailableExamMode() { - if (GlobalPreferences::sharedGlobalPreferences()->availableExamModes() == I18n::AvailableExamModes::StandardOnly + if (GlobalPreferences::sharedGlobalPreferences()->availableExamModes() == CountryPreferences::AvailableExamModes::StandardOnly || GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { return 1; } - assert(GlobalPreferences::sharedGlobalPreferences()->availableExamModes() == I18n::AvailableExamModes::All); + assert(GlobalPreferences::sharedGlobalPreferences()->availableExamModes() == CountryPreferences::AvailableExamModes::All); return 2; } diff --git a/apps/global_preferences.h b/apps/global_preferences.h index 66996dc46..c6c20ff8b 100644 --- a/apps/global_preferences.h +++ b/apps/global_preferences.h @@ -16,9 +16,9 @@ public: void setLanguage(I18n::Language language) { m_language = language; } I18n::Country country() const { return m_country; } void setCountry(I18n::Country country) { m_country = country; } - I18n::AvailableExamModes availableExamModes() const { return I18n::CountryPreferencesArray[static_cast(m_country)].availableExamModes; } - I18n::MethodForQuartiles methodForQuartiles() const { return I18n::CountryPreferencesArray[static_cast(m_country)].methodForQuartiles; } - Poincare::Preferences::UnitFormat unitFormat() const { return I18n::CountryPreferencesArray[static_cast(m_country)].unitFormat; } + CountryPreferences::AvailableExamModes availableExamModes() const { return I18n::CountryPreferencesArray[static_cast(m_country)].availableExamModes(); } + CountryPreferences::MethodForQuartiles methodForQuartiles() const { return I18n::CountryPreferencesArray[static_cast(m_country)].methodForQuartiles(); } + Poincare::Preferences::UnitFormat unitFormat() const { return I18n::CountryPreferencesArray[static_cast(m_country)].unitFormat(); } bool isInExamMode() const { return (int8_t)examMode() > 0; } ExamMode examMode() const; void setExamMode(ExamMode examMode); diff --git a/apps/i18n.py b/apps/i18n.py index 2c7c08aa5..83bcdfb8a 100644 --- a/apps/i18n.py +++ b/apps/i18n.py @@ -6,11 +6,12 @@ # properly draw upper case letters with accents, we remove them here. # It works with Python 2 and Python 3 -import sys -import re -import unicodedata import argparse +import csv import io +import re +import sys +import unicodedata parser = argparse.ArgumentParser(description="Process some i18n files.") @@ -19,6 +20,7 @@ parser.add_argument('--implementation', help='the .cpp file to generate') parser.add_argument('--locales', nargs='+', help='locale to actually generate') parser.add_argument('--countries', nargs='+', help='countries to actually generate') parser.add_argument('--codepoints', help='the code_points.h file') +parser.add_argument('--countrypreferences', help='the country_preferences.csv file') parser.add_argument('--files', nargs='+', help='an i18n file') parser.add_argument('--generateISO6391locales', type=int, nargs='+', help='whether to generate the ISO6391 codes for the languages (for instance "en" for english)') @@ -115,6 +117,17 @@ def parse_codepoints(file): codepoints = parse_codepoints(args.codepoints) +def parse_country_preferences(file): + countryPreferences = {} + with io.open(file, "r", encoding="utf-8") as csvfile: + csvreader = csv.reader(csvfile, delimiter=',') + headers = next(csvreader, None) + for row in csvreader: + countryPreferences[row[0]] = [headers[i] + "::" + row[i] for i in range(1, len(row))] + return countryPreferences + +countryPreferences = parse_country_preferences(args.countrypreferences) + def print_block_from_list(target, header, data, beautify=lambda arg: arg, prefix=" ", footer="};\n\n"): target.write(header) for i in range(len(data)): @@ -127,7 +140,7 @@ def print_header(data, path, locales, countries): f.write("#define APPS_I18N_H\n\n") f.write("// This file is auto-generated by i18n.py\n\n") f.write("#include \n") - f.write("#include \n\n") + f.write("#include \n\n") f.write("namespace I18n {\n\n") f.write("constexpr static int NumberOfLanguages = %d;\n\n" % len(locales)) f.write("constexpr static int NumberOfCountries = %d;\n\n" % len(countries)) @@ -175,35 +188,13 @@ def print_header(data, path, locales, countries): " Message::Country") # Country preferences - f.write("enum class AvailableExamModes : uint8_t {\n") - f.write(" None,\n") - f.write(" StandardOnly,\n") - f.write(" All\n") - f.write("};\n\n") - f.write("enum class MethodForQuartiles : uint8_t {\n") - f.write(" MedianOfSublist,\n") - f.write(" CumulatedFrequency\n") - f.write("};\n\n") - f.write("struct CountryPreferences {\n") - f.write(" AvailableExamModes availableExamModes;\n") - f.write(" MethodForQuartiles methodForQuartiles;\n") - f.write(" Poincare::Preferences::UnitFormat unitFormat;\n") - f.write("};\n\n") - countryPreferences = { - 'CA':"CountryPreferences{AvailableExamModes::StandardOnly, MethodForQuartiles::MedianOfSublist, Poincare::Preferences::UnitFormat::Metric}", - 'DE':"CountryPreferences{AvailableExamModes::StandardOnly, MethodForQuartiles::MedianOfSublist, Poincare::Preferences::UnitFormat::Metric}", - 'ES':"CountryPreferences{AvailableExamModes::StandardOnly, MethodForQuartiles::MedianOfSublist, Poincare::Preferences::UnitFormat::Metric}", - 'FR':"CountryPreferences{AvailableExamModes::StandardOnly, MethodForQuartiles::CumulatedFrequency, Poincare::Preferences::UnitFormat::Metric}", - 'GB':"CountryPreferences{AvailableExamModes::StandardOnly, MethodForQuartiles::MedianOfSublist, Poincare::Preferences::UnitFormat::Metric}", - 'IT':"CountryPreferences{AvailableExamModes::StandardOnly, MethodForQuartiles::CumulatedFrequency, Poincare::Preferences::UnitFormat::Metric}", - 'NL':"CountryPreferences{AvailableExamModes::All, MethodForQuartiles::MedianOfSublist, Poincare::Preferences::UnitFormat::Metric}", - 'PT':"CountryPreferences{AvailableExamModes::StandardOnly, MethodForQuartiles::MedianOfSublist, Poincare::Preferences::UnitFormat::Metric}", - 'US':"CountryPreferences{AvailableExamModes::StandardOnly, MethodForQuartiles::MedianOfSublist, Poincare::Preferences::UnitFormat::Imperial}", - 'WW':"CountryPreferences{AvailableExamModes::All, MethodForQuartiles::MedianOfSublist, Poincare::Preferences::UnitFormat::Metric}"} f.write("constexpr static CountryPreferences CountryPreferencesArray[] = {\n") for country in countries: - key = country if (country in countryPreferences) else 'WW' - f.write(" " + countryPreferences[key] + ",\n") + key = country if (country in countryPreferences) else 'inl' + line = " CountryPreferences(" + for param in countryPreferences[key]: + line += param + ", " + f.write(line[:-2] + "),\n") f.write("};\n\n") f.write("}\n\n") diff --git a/apps/statistics/store.cpp b/apps/statistics/store.cpp index 6d7465991..219f4c8dc 100644 --- a/apps/statistics/store.cpp +++ b/apps/statistics/store.cpp @@ -198,18 +198,18 @@ double Store::sampleStandardDeviation(int series) const { * the more general definition if non-integral frequencies are found. * */ double Store::firstQuartile(int series) const { - if (GlobalPreferences::sharedGlobalPreferences()->methodForQuartiles() == I18n::MethodForQuartiles::CumulatedFrequency || !frequenciesAreInteger(series)) { + if (GlobalPreferences::sharedGlobalPreferences()->methodForQuartiles() == CountryPreferences::MethodForQuartiles::CumulatedFrequency || !frequenciesAreInteger(series)) { return sortedElementAtCumulatedFrequency(series, 1.0/4.0); } - assert(GlobalPreferences::sharedGlobalPreferences()->methodForQuartiles() == I18n::MethodForQuartiles::MedianOfSublist); + assert(GlobalPreferences::sharedGlobalPreferences()->methodForQuartiles() == CountryPreferences::MethodForQuartiles::MedianOfSublist); return sortedElementAtCumulatedPopulation(series, std::floor(sumOfOccurrences(series) / 2.) / 2., true); } double Store::thirdQuartile(int series) const { - if (GlobalPreferences::sharedGlobalPreferences()->methodForQuartiles() == I18n::MethodForQuartiles::CumulatedFrequency || !frequenciesAreInteger(series)) { + if (GlobalPreferences::sharedGlobalPreferences()->methodForQuartiles() == CountryPreferences::MethodForQuartiles::CumulatedFrequency || !frequenciesAreInteger(series)) { return sortedElementAtCumulatedFrequency(series, 3.0/4.0); } - assert(GlobalPreferences::sharedGlobalPreferences()->methodForQuartiles() == I18n::MethodForQuartiles::MedianOfSublist); + assert(GlobalPreferences::sharedGlobalPreferences()->methodForQuartiles() == CountryPreferences::MethodForQuartiles::MedianOfSublist); return sortedElementAtCumulatedPopulation(series, std::ceil(3./2. * sumOfOccurrences(series)) / 2., true); } diff --git a/apps/statistics/test/store.cpp b/apps/statistics/test/store.cpp index e56645160..18d0aac24 100644 --- a/apps/statistics/test/store.cpp +++ b/apps/statistics/test/store.cpp @@ -103,7 +103,7 @@ void assert_data_statictics_equal_to( GlobalPreferences::sharedGlobalPreferences()->setCountry(country); quartileRange = store.quartileRange(seriesIndex); quiz_assert(quartileRange >= 0.0); - shouldUseFrequencyMethod = GlobalPreferences::sharedGlobalPreferences()->methodForQuartiles() == I18n::MethodForQuartiles::CumulatedFrequency; + shouldUseFrequencyMethod = GlobalPreferences::sharedGlobalPreferences()->methodForQuartiles() == CountryPreferences::MethodForQuartiles::CumulatedFrequency; assert_value_approximately_equal_to(store.firstQuartile(seriesIndex), shouldUseFrequencyMethod ? trueFirstQuartileFrequencyMethod : trueFirstQuartileSublistMethod, precision, reference); assert_value_approximately_equal_to(store.thirdQuartile(seriesIndex), shouldUseFrequencyMethod ? trueThirdQuartileFrequencyMethod : trueThirdQuartileSublistMethod, precision, reference); assert_value_approximately_equal_to(quartileRange, shouldUseFrequencyMethod ? trueQuartileRangeFrequencyMethod : trueQuartileRangeSublistMethod, 0.0, 0.0);