From 3d3b13c8adea47f141f076dee2d8325ef4783f1c Mon Sep 17 00:00:00 2001 From: Paul Franklin Date: Sun, 9 Apr 2017 15:21:08 -0700 Subject: [PATCH] 9985: secondary locales do not use their own numeric date format --- gramps/gen/datehandler/__init__.py | 27 +++++--- gramps/gen/datehandler/_date_ar.py | 3 +- gramps/gen/datehandler/_date_bg.py | 5 +- gramps/gen/datehandler/_date_ca.py | 5 +- gramps/gen/datehandler/_date_cs.py | 39 +++++++----- gramps/gen/datehandler/_date_da.py | 4 +- gramps/gen/datehandler/_date_de.py | 9 +-- gramps/gen/datehandler/_date_el.py | 3 +- gramps/gen/datehandler/_date_es.py | 4 +- gramps/gen/datehandler/_date_fi.py | 5 +- gramps/gen/datehandler/_date_fr.py | 31 ++++----- gramps/gen/datehandler/_date_hr.py | 5 +- gramps/gen/datehandler/_date_hu.py | 5 +- gramps/gen/datehandler/_date_is.py | 17 ++++- gramps/gen/datehandler/_date_it.py | 3 +- gramps/gen/datehandler/_date_ja.py | 27 ++++---- gramps/gen/datehandler/_date_lt.py | 12 +++- gramps/gen/datehandler/_date_nb.py | 6 +- gramps/gen/datehandler/_date_nl.py | 7 ++- gramps/gen/datehandler/_date_pl.py | 7 ++- gramps/gen/datehandler/_date_pt.py | 5 +- gramps/gen/datehandler/_date_ru.py | 4 +- gramps/gen/datehandler/_date_sk.py | 4 +- gramps/gen/datehandler/_date_sl.py | 9 +-- gramps/gen/datehandler/_date_sr.py | 16 ++--- gramps/gen/datehandler/_date_sv.py | 4 +- gramps/gen/datehandler/_date_uk.py | 5 +- gramps/gen/datehandler/_date_zh_CN.py | 5 +- gramps/gen/datehandler/_date_zh_TW.py | 5 +- gramps/gen/datehandler/_datedisplay.py | 75 ++++++++++++++++------ gramps/gen/datehandler/_datehandler.py | 49 ++++++++++++--- gramps/gen/datehandler/_dateparser.py | 45 +++++++++---- gramps/gen/datehandler/_datestrings.py | 2 +- gramps/gen/datehandler/_dateutils.py | 4 +- gramps/gen/datehandler/_grampslocale.py | 74 ++++++++-------------- gramps/gen/plug/report/_reportbase.py | 9 ++- gramps/gen/utils/grampslocale.py | 84 ++++++++++++++++++++----- gramps/plugins/lib/libgedcom.py | 9 ++- 38 files changed, 424 insertions(+), 208 deletions(-) diff --git a/gramps/gen/datehandler/__init__.py b/gramps/gen/datehandler/__init__.py index 73b55b24f..6aa648126 100644 --- a/gramps/gen/datehandler/__init__.py +++ b/gramps/gen/datehandler/__init__.py @@ -2,6 +2,7 @@ # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2004-2007 Donald N. Allingham +# Copyright (C) 2017 Paul Franklin # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -29,11 +30,16 @@ Class handling language-specific selection for date parser and displayer. #------------------------------------------------------------------------- import logging +#------------------------------------------------------------------------- +# +# Gramps modules +# +#------------------------------------------------------------------------- from ..const import GRAMPS_LOCALE as glocale _ = glocale.translation.sgettext # import prerequisites for localized handlers from ._datehandler import (LANG, LANG_SHORT, LANG_TO_PARSER, LANG_TO_DISPLAY, - register_datehandler) + locale_tformat, main_locale) from . import _datestrings # Import all the localized handlers @@ -69,12 +75,13 @@ from . import _date_zh_TW # Initialize global parser try: if LANG in LANG_TO_PARSER: - parser = LANG_TO_PARSER[LANG]() + parser = LANG_TO_PARSER[LANG](plocale=glocale) else: - parser = LANG_TO_PARSER[LANG_SHORT]() + parser = LANG_TO_PARSER[LANG_SHORT](plocale=glocale) except: - logging.warning(_("Date parser for '%s' not available, using default") % LANG) - parser = LANG_TO_PARSER["C"]() + logging.warning( + _("Date parser for '%s' not available, using default") % LANG) + parser = LANG_TO_PARSER["C"](plocale=glocale) # Initialize global displayer try: @@ -85,17 +92,17 @@ except: try: if LANG in LANG_TO_DISPLAY: - displayer = LANG_TO_DISPLAY[LANG](val) + displayer = LANG_TO_DISPLAY[LANG](val, blocale=glocale) else: - displayer = LANG_TO_DISPLAY[LANG_SHORT](val) + displayer = LANG_TO_DISPLAY[LANG_SHORT](val, blocale=glocale) except: - logging.warning(_("Date displayer for '%s' not available, using default") % LANG) - displayer = LANG_TO_DISPLAY["C"](val) + logging.warning( + _("Date displayer for '%s' not available, using default") % LANG) + displayer = LANG_TO_DISPLAY["C"](val, blocale=glocale) # Import utility functions from ._dateutils import * -from ._grampslocale import (codeset, tformat) # set GRAMPS_RESOURCES then: python3 -m gramps.gen.datehandler.__init__ if __name__ == "__main__": diff --git a/gramps/gen/datehandler/_date_ar.py b/gramps/gen/datehandler/_date_ar.py index ebf9d2342..8b96bfca1 100644 --- a/gramps/gen/datehandler/_date_ar.py +++ b/gramps/gen/datehandler/_date_ar.py @@ -229,5 +229,6 @@ class DateDisplayAR(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('ar_AR', 'ar', 'Arabic', 'arabic'), +register_datehandler( + ('ar_EG', 'ar_AR', 'ar', 'Arabic', 'arabic', ('%d %b, %Y',)), DateParserAR, DateDisplayAR) diff --git a/gramps/gen/datehandler/_date_bg.py b/gramps/gen/datehandler/_date_bg.py index 086b8cca5..3ea050a8e 100644 --- a/gramps/gen/datehandler/_date_bg.py +++ b/gramps/gen/datehandler/_date_bg.py @@ -315,7 +315,7 @@ class DateDisplayBG(DateDisplay): if date_val[0] == date_val[1] == 0: return str(date_val[2]) else: - value = self._tformat.replace('%m', str(date_val[1])) + value = self.dhformat.replace('%m', str(date_val[1])) # some locales have %b for the month, e.g. ar_EG, is_IS, nb_NO value = value.replace('%b', str(date_val[1])) if date_val[0] == 0: # ignore the zero day and its delimiter @@ -330,5 +330,6 @@ class DateDisplayBG(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('bg_BG', 'bg', 'bulgarian', 'Bulgarian'), +register_datehandler( + ('bg_BG', 'bg', 'bulgarian', 'Bulgarian', ('%e.%m.%Y',)), DateParserBG, DateDisplayBG) diff --git a/gramps/gen/datehandler/_date_ca.py b/gramps/gen/datehandler/_date_ca.py index 8802d2199..688c990f1 100644 --- a/gramps/gen/datehandler/_date_ca.py +++ b/gramps/gen/datehandler/_date_ca.py @@ -193,4 +193,7 @@ class DateDisplayCA(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('ca_ES', 'ca', 'català', 'Catalan', 'ca_FR', 'ca_AD', 'ca_IT'), DateParserCA, DateDisplayCA) +register_datehandler( + ('ca_ES', 'ca', 'català', 'Catalan', + 'ca_FR', 'ca_AD', 'ca_IT', ('%d/%m/%Y',)), + DateParserCA, DateDisplayCA) diff --git a/gramps/gen/datehandler/_date_cs.py b/gramps/gen/datehandler/_date_cs.py index 14f8969c8..7911053a4 100644 --- a/gramps/gen/datehandler/_date_cs.py +++ b/gramps/gen/datehandler/_date_cs.py @@ -171,8 +171,10 @@ class DateParserCZ(DateParser): 'vyp.' : Date.QUAL_CALCULATED, } - # bug 9739 _grampslocale.py gets '%-d.%-m.%Y' and makes it be '%/d.%/m.%Y' - fmt = DateParser.fmt.replace('/', '') # so counteract that + def dhformat_changed(self): + """ Allow overriding so a subclass can modify it """ + # bug 9739 grampslocale.py gets '%-d.%-m.%Y' -- makes it be '%/d.%/m.%Y' + self.dhformat = self.dhformat.replace('/', '') # so counteract that def init_strings(self): DateParser.init_strings(self) @@ -215,21 +217,24 @@ class DateDisplayCZ(DateDisplay): bce = ["před naším letopočtem", "před Kristem", "př. n. l.", "př. Kr."] + DateParser.bce - formats = ( - "ISO (rrrr-mm-dd)", - "numerický", - "měsíc den, Rok", - "měs den, Rok", - "den. měsíc rok", - "den. měs rok" - ) - # this must agree with DateDisplayEn's "formats" definition - # (since no locale-specific _display_gregorian exists, here) - display = DateDisplay.display_formatted - # bug 9537 _grampslocale.py gets '%-d.%-m.%Y' and makes it be '%/d.%/m.%Y' - _tformat = DateDisplay._tformat.replace('/', '') # so counteract that + def formats_changed(self): + """ Allow overriding so a subclass can modify """ + + # bug 9537 grampslocale.py gets '%-d.%-m.%Y' -- makes it be '%/d.%/m.%Y' + self.dhformat = self.dhformat.replace('/', '') # so counteract that + + self.formats = ( + "ISO (rrrr-mm-dd)", + "numerický", + "měsíc den, Rok", + "měs den, Rok", + "den. měsíc rok", + "den. měs rok" + ) + # this must agree with DateDisplayEn's "formats" definition + # (since no locale-specific _display_gregorian exists, here) def orig_display(self, date): # unused: only here for historical reference """ @@ -278,4 +283,6 @@ class DateDisplayCZ(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(("cs", "CS", "cs_CZ", "Czech"), DateParserCZ, DateDisplayCZ) +register_datehandler( + ("cs_CZ", "cs", "CS", "Czech", ('%-d.%-m.%Y',)), + DateParserCZ, DateDisplayCZ) diff --git a/gramps/gen/datehandler/_date_da.py b/gramps/gen/datehandler/_date_da.py index 4eb4a44e1..fcd0a9b19 100644 --- a/gramps/gen/datehandler/_date_da.py +++ b/gramps/gen/datehandler/_date_da.py @@ -176,4 +176,6 @@ class DateDisplayDa(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('da_DK', 'da', 'dansk', 'Danish'), DateParserDa, DateDisplayDa) +register_datehandler( + ('da_DK', 'da', 'dansk', 'Danish', ('%d-%m-%Y',)), + DateParserDa, DateDisplayDa) diff --git a/gramps/gen/datehandler/_date_de.py b/gramps/gen/datehandler/_date_de.py index 9df66902f..5efc4a9ff 100644 --- a/gramps/gen/datehandler/_date_de.py +++ b/gramps/gen/datehandler/_date_de.py @@ -237,7 +237,7 @@ class DateDisplayDE(DateDisplay): if date_val[0] == date_val[1] == 0: value = str(date_val[2]) else: - value = self._tformat.replace('%m', str(date_val[1])) + value = self.dhformat.replace('%m', str(date_val[1])) value = value.replace('%d', str(date_val[0])) value = value.replace('%Y', str(date_val[2])) elif self.format == 2: @@ -321,6 +321,7 @@ class DateDisplayDE(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('de_DE', 'german', 'German', 'de_AT', 'de_CH', - 'de_LI', 'de_LU', 'de_BE', 'de'), - DateParserDE, DateDisplayDE) +register_datehandler( + ('de_DE', 'german', 'German', 'de_AT', 'de_CH', + 'de_LI', 'de_LU', 'de_BE', 'de', ('%d.%m.%Y',)), + DateParserDE, DateDisplayDE) diff --git a/gramps/gen/datehandler/_date_el.py b/gramps/gen/datehandler/_date_el.py index 888924ade..e1425132e 100644 --- a/gramps/gen/datehandler/_date_el.py +++ b/gramps/gen/datehandler/_date_el.py @@ -242,5 +242,6 @@ class DateDisplayEL(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('el_GR', 'el_CY', 'el', 'Greek', 'greek'), +register_datehandler( + ('el_GR', 'el_CY', 'el', 'Greek', 'greek', ('%d/%m/%Y',)), DateParserEL, DateDisplayEL) diff --git a/gramps/gen/datehandler/_date_es.py b/gramps/gen/datehandler/_date_es.py index 13b0f40ca..f1ce90786 100644 --- a/gramps/gen/datehandler/_date_es.py +++ b/gramps/gen/datehandler/_date_es.py @@ -177,4 +177,6 @@ class DateDisplayES(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('es_ES', 'es', 'spanish', 'Spanish'), DateParserES, DateDisplayES) +register_datehandler( + ('es_ES', 'es', 'spanish', 'Spanish', ('%d/%m/%Y',)), + DateParserES, DateDisplayES) diff --git a/gramps/gen/datehandler/_date_fi.py b/gramps/gen/datehandler/_date_fi.py index ebf7edc60..18f31e4f0 100644 --- a/gramps/gen/datehandler/_date_fi.py +++ b/gramps/gen/datehandler/_date_fi.py @@ -178,5 +178,6 @@ class DateDisplayFI(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('fi_FI', 'fi', 'finnish', 'Finnish'), - DateParserFI, DateDisplayFI) +register_datehandler( + ('fi_FI', 'fi', 'finnish', 'Finnish', ('%d.%m.%Y',)), + DateParserFI, DateDisplayFI) diff --git a/gramps/gen/datehandler/_date_fr.py b/gramps/gen/datehandler/_date_fr.py index 5cf4ee599..b7f21e012 100644 --- a/gramps/gen/datehandler/_date_fr.py +++ b/gramps/gen/datehandler/_date_fr.py @@ -42,7 +42,6 @@ from ..lib.date import Date from ._dateparser import DateParser from ._datedisplay import DateDisplay from ._datehandler import register_datehandler -from . import _grampslocale #------------------------------------------------------------------------- # @@ -232,22 +231,24 @@ class DateDisplayFR(DateDisplay): _bce_str = "%s avant le calendrier" - # Replace the previous "Numérique" by a string which - # do have an explicit meaning: "System default (format)" - _locale_tformat = _grampslocale.tformat - _locale_tformat = _locale_tformat.replace('%d', "J") - _locale_tformat = _locale_tformat.replace('%m', "M") - _locale_tformat = _locale_tformat.replace('%Y', "A") + def formats_changed(self): + """ Allow overriding so a subclass can modify """ - formats = ("AAAA-MM-JJ (ISO)", # 0 - "Défaut système (" + _locale_tformat + ")", # 1 + # Replace the previous "Numérique" by a string which + # do have an explicit meaning: "System default (format)" + example = self.dhformat + example = example.replace('%d', "J") + example = example.replace('%m', "M") + example = example.replace('%Y', "A") + + self.formats = ("AAAA-MM-JJ (ISO)", # 0 + "Défaut système (" + example + ")", # 1 "Jour Mois Année", # 2 "Jour MOI Année", # 3 "Jour. Mois Année", # 4 "Jour. MOI Année", # 5 "Mois Jour, Année", # 6 "MOI Jour, Année",) # 7 - # this definition must agree with its "_display_gregorian" method def _display_gregorian(self, date_val, **kwargs): @@ -263,7 +264,7 @@ class DateDisplayFR(DateDisplay): return self.display_iso(date_val) elif self.format == 1: - # ISO + # numerical if date_val[2] < 0 or date_val[3]: return self.display_iso(date_val) @@ -271,7 +272,7 @@ class DateDisplayFR(DateDisplay): if date_val[0] == date_val[1] == 0: value = str(date_val[2]) else: - value = self._tformat.replace('%m', str(date_val[1])) + value = self.dhformat.replace('%m', str(date_val[1])) value = value.replace('%d', str(date_val[0])) # base_display : @@ -380,5 +381,7 @@ class DateDisplayFR(DateDisplay): # #------------------------------------------------------------------------- -register_datehandler(('fr_FR', 'fr', 'french', 'French', 'fr_CA', - 'fr_BE', 'fr_CH'), DateParserFR, DateDisplayFR) +register_datehandler( + ('fr_FR', 'fr', 'french', 'French', 'fr_CA', + 'fr_BE', 'fr_CH', ('%d/%m/%Y',)), + DateParserFR, DateDisplayFR) diff --git a/gramps/gen/datehandler/_date_hr.py b/gramps/gen/datehandler/_date_hr.py index 33a19e043..a411b8649 100644 --- a/gramps/gen/datehandler/_date_hr.py +++ b/gramps/gen/datehandler/_date_hr.py @@ -110,5 +110,6 @@ class DateDisplayHR(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('hr', 'HR', 'croatian', 'Croatian', 'hrvatski', 'hr_HR'), - DateParserHR, DateDisplayHR) +register_datehandler( + ('hr_HR', 'hr', 'HR', 'croatian', 'Croatian', 'hrvatski', ('%d.%m.%Y',)), + DateParserHR, DateDisplayHR) diff --git a/gramps/gen/datehandler/_date_hu.py b/gramps/gen/datehandler/_date_hu.py index 27d513fd5..ffadc03fd 100644 --- a/gramps/gen/datehandler/_date_hu.py +++ b/gramps/gen/datehandler/_date_hu.py @@ -364,5 +364,6 @@ class DateDisplayHU(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('hu_HU', 'hu', 'hungarian', 'Hungarian', 'magyar'), - DateParserHU, DateDisplayHU) +register_datehandler( + ('hu_HU', 'hu', 'hungarian', 'Hungarian', 'magyar', ('%Y-%m-%d',)), + DateParserHU, DateDisplayHU) diff --git a/gramps/gen/datehandler/_date_is.py b/gramps/gen/datehandler/_date_is.py index ed3de623c..bbc553cac 100644 --- a/gramps/gen/datehandler/_date_is.py +++ b/gramps/gen/datehandler/_date_is.py @@ -89,8 +89,19 @@ class DateParserIs(DateParser): 'reiknað' : Date.QUAL_CALCULATED, } + def dhformat_changed(self): + self._dhformat_parse = re.compile(".*%(\S).*%(\S).*%(\S).*%(\S).*") + def init_strings(self): DateParser.init_strings(self) + + # match 'day. month year' format + self._text2 = re.compile('(\d+)?\.?\s*?%s\.?\s*((\d+)(/\d+)?)?\s*$' + % self._mon_str, re.IGNORECASE) + # match 'short-day day.month year' format + short_day_str = '(' + '|'.join(self._ds.short_days[1:]) + ')' + self._numeric = re.compile("%s\s*((\d+)[\.]\s*)?((\d+)\s*)?(\d+)\s*$" + % short_day_str, re.IGNORECASE) self._span = re.compile("(frá)?\s*(?P.+)\s*(til|--|–)\s*(?P.+)", re.IGNORECASE) self._range = re.compile("(milli)\s+(?P.+)\s+og\s+(?P.+)", @@ -189,7 +200,7 @@ class DateDisplayIs(DateDisplay): if date_val[0] == date_val[1] == 0: return str(date_val[2]) else: - value = self._tformat.replace('%m', str(date_val[1])) + value = self.dhformat.replace('%m', str(date_val[1])) # some locales have %b for the month, e.g. ar_EG, is_IS, nb_NO value = value.replace('%b', str(date_val[1])) # some locales have %a for the abbreviated day, e.g. is_IS @@ -206,4 +217,6 @@ class DateDisplayIs(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('is_IS', 'is', 'íslenskt', 'Icelandic'), DateParserIs, DateDisplayIs) +register_datehandler( + ('is_IS', 'is', 'íslenskt', 'Icelandic', ('%a %e.%b %Y',)), + DateParserIs, DateDisplayIs) diff --git a/gramps/gen/datehandler/_date_it.py b/gramps/gen/datehandler/_date_it.py index e501abf6a..863c5d4f8 100644 --- a/gramps/gen/datehandler/_date_it.py +++ b/gramps/gen/datehandler/_date_it.py @@ -189,5 +189,6 @@ class DateDisplayIT(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('it_IT', 'it', 'italian', 'Italian', 'it_CH'), +register_datehandler( + ('it_IT', 'it', 'italian', 'Italian', 'it_CH', ('%d/%m/%Y',)), DateParserIT, DateDisplayIT) diff --git a/gramps/gen/datehandler/_date_ja.py b/gramps/gen/datehandler/_date_ja.py index 3b6d125ff..d60d6fca2 100644 --- a/gramps/gen/datehandler/_date_ja.py +++ b/gramps/gen/datehandler/_date_ja.py @@ -42,7 +42,6 @@ from ..lib.date import Date from ._dateparser import DateParser from ._datedisplay import DateDisplay from ._datehandler import register_datehandler -from . import _grampslocale #------------------------------------------------------------------------- # @@ -185,15 +184,18 @@ class DateDisplayJA(DateDisplay): Japanese language date display class. """ - # Specify what is actually the "System Default". - _locale_tformat = _grampslocale.tformat - _locale_tformat = _locale_tformat.replace('%d', "31") - _locale_tformat = _locale_tformat.replace('%m', "12") - _locale_tformat = _locale_tformat.replace('%Y', "1999") + def formats_changed(self): + """ Allow overriding so a subclass can modify """ - # This definition must agree with its "_display_gregorian" method - formats = ("YYYY-MM-DD (ISO)", # 0 - "システムデフォールト (" + _locale_tformat + ")", # 1 + # Specify what is actually the "System Default". + example = self.dhformat + example = example.replace('%d', "31") + example = example.replace('%m', "12") + example = example.replace('%Y', "1999") + + # This definition must agree with its "_display_gregorian" method + self. formats = ("YYYY-MM-DD (ISO)", # 0 + "システムデフォールト (" + example + ")", # 1 "1999年12月31日", # 2 "1999年十二月31日", # 3 ) @@ -216,7 +218,7 @@ class DateDisplayJA(DateDisplay): if date_val[0] == date_val[1] == 0: value = str(date_val[2]) else: - value = self._tformat.replace('%m', str(date_val[1])) + value = self.dhformat.replace('%m', str(date_val[1])) if date_val[0] == 0: # ignore the zero day and its delimiter i_day = value.find('%d') value = value.replace(value[i_day:i_day+3], '') @@ -265,5 +267,6 @@ class DateDisplayJA(DateDisplay): # #------------------------------------------------------------------------- -register_datehandler(('ja_JP', 'ja', 'japanese', 'Japanese'), - DateParserJA, DateDisplayJA) +register_datehandler( + ('ja_JP', 'ja', 'japanese', 'Japanese', ('%Y年%m月%d日',)), + DateParserJA, DateDisplayJA) diff --git a/gramps/gen/datehandler/_date_lt.py b/gramps/gen/datehandler/_date_lt.py index e688bc1e2..95d0bb037 100644 --- a/gramps/gen/datehandler/_date_lt.py +++ b/gramps/gen/datehandler/_date_lt.py @@ -182,7 +182,8 @@ class DateDisplayLT(DateDisplay): _qual_str = ("", "apytikriai ", "apskaičiuota ") formats = ( - "mmmm-MM-DD (ISO)", "mmmm m. mėnesio diena d.", "Mėn diena, metai") + "mmmm-MM-DD (ISO)", "mmmm.MM.DD", + "mmmm m. mėnesio diena d.", "Mėn diena, metai") # this definition must agree with its "_display_gregorian" method def _display_gregorian(self, date_val): @@ -195,6 +196,9 @@ class DateDisplayLT(DateDisplay): if self.format == 0: return self.display_iso(date_val) elif self.format == 1: + # numerical + return self.dd_dformat01(date_val) + elif self.format == 2: # mmmm m. mėnesio diena d. (year m. month_name day d.) if date_val[0] == 0: if date_val[1] == 0: @@ -205,7 +209,7 @@ class DateDisplayLT(DateDisplay): value = "%s m. %s %d d." % (year, self.long_months[date_val[1]], date_val[0]) - elif self.format == 2: + elif self.format == 3: # month_abbreviation day, year if date_val[0] == 0: if date_val[1] == 0: @@ -259,4 +263,6 @@ class DateDisplayLT(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('lt_LT', 'lt', 'lithuanian', 'Lithuanian'), DateParserLT, DateDisplayLT) +register_datehandler( + ('lt_LT', 'lt', 'lithuanian', 'Lithuanian', ('%Y.%m.%d',)), + DateParserLT, DateDisplayLT) diff --git a/gramps/gen/datehandler/_date_nb.py b/gramps/gen/datehandler/_date_nb.py index a45e3b380..676290437 100644 --- a/gramps/gen/datehandler/_date_nb.py +++ b/gramps/gen/datehandler/_date_nb.py @@ -89,6 +89,8 @@ class DateParserNb(DateParser): def init_strings(self): DateParser.init_strings(self) + # match day. month year + self._numeric = re.compile("((\d+)[\.])?\s*((\d+))?\s*(\d+)$") self._span = re.compile("(fra)?\s*(?P.+)\s*(til|--|–)\s*(?P.+)", re.IGNORECASE) self._range = re.compile("(mellom)\s+(?P.+)\s+og\s+(?P.+)", @@ -176,4 +178,6 @@ class DateDisplayNb(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('nb_NO', 'nb', 'nn_NO', 'nn', 'norsk', 'Norwegian'), DateParserNb, DateDisplayNb) +register_datehandler( + ('nb_NO', 'nb', 'nn_NO', 'nn', 'norsk', 'Norwegian', ('%d. %b %Y',)), + DateParserNb, DateDisplayNb) diff --git a/gramps/gen/datehandler/_date_nl.py b/gramps/gen/datehandler/_date_nl.py index b8870aef6..bcdf94bbd 100644 --- a/gramps/gen/datehandler/_date_nl.py +++ b/gramps/gen/datehandler/_date_nl.py @@ -180,7 +180,7 @@ class DateDisplayNL(DateDisplay): if date_val[0] == date_val[1] == 0: value = str(date_val[2]) else: - value = self._tformat.replace('%m', str(date_val[1])) + value = self.dhformat.replace('%m', str(date_val[1])) value = value.replace('%d', str(date_val[0])) value = value.replace('%Y', str(abs(date_val[2]))) value = value.replace('-', '/') @@ -268,5 +268,6 @@ class DateDisplayNL(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('nl_NL', 'dutch', 'Dutch', 'nl_BE', 'nl'), - DateParserNL, DateDisplayNL) +register_datehandler( + ('nl_NL', 'dutch', 'Dutch', 'nl_BE', 'nl', ('%d-%m-%Y',)), + DateParserNL, DateDisplayNL) diff --git a/gramps/gen/datehandler/_date_pl.py b/gramps/gen/datehandler/_date_pl.py index 736be5459..acfa6ec5d 100644 --- a/gramps/gen/datehandler/_date_pl.py +++ b/gramps/gen/datehandler/_date_pl.py @@ -231,7 +231,7 @@ class DateDisplayPL(DateDisplay): if date_val[0] == date_val[1] == 0: value = str(date_val[2]) else: - value = self._tformat.replace('%d', str(date_val[0])) + value = self.dhformat.replace('%d', str(date_val[0])) value = value.replace('%m', str(date_val[1])) value = value.replace('%Y', str(date_val[2])) elif self.format == 2: @@ -317,5 +317,6 @@ class DateDisplayPL(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('pl_PL','polish','Polish_Poland','pl'), - DateParserPL, DateDisplayPL) +register_datehandler( + ('pl_PL', 'polish', 'Polish_Poland', 'pl', ('%d.%m.%Y',)), + DateParserPL, DateDisplayPL) diff --git a/gramps/gen/datehandler/_date_pt.py b/gramps/gen/datehandler/_date_pt.py index 48bd501d5..2de57bbf8 100644 --- a/gramps/gen/datehandler/_date_pt.py +++ b/gramps/gen/datehandler/_date_pt.py @@ -180,4 +180,7 @@ class DateDisplayPT(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('pt', 'pt_PT', 'pt_PT.UTF-8', 'pt_BR', 'pt_BR.UTF-8', 'pt', 'portuguese', 'Portuguese'), DateParserPT, DateDisplayPT) +register_datehandler( + ('pt_PT', 'pt_PT.UTF-8', 'pt_BR', 'pt_BR.UTF-8', + 'pt' 'portuguese', 'Portuguese', ('%d-%m-%Y',)), + DateParserPT, DateDisplayPT) diff --git a/gramps/gen/datehandler/_date_ru.py b/gramps/gen/datehandler/_date_ru.py index 04c5af603..f435d4083 100644 --- a/gramps/gen/datehandler/_date_ru.py +++ b/gramps/gen/datehandler/_date_ru.py @@ -162,4 +162,6 @@ class DateDisplayRU(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('ru_RU', 'ru', 'russian', 'Russian'), DateParserRU, DateDisplayRU) +register_datehandler( + ('ru_RU', 'ru', 'russian', 'Russian', ('%d.%m.%Y',)), + DateParserRU, DateDisplayRU) diff --git a/gramps/gen/datehandler/_date_sk.py b/gramps/gen/datehandler/_date_sk.py index 1f17a9289..24c785e9e 100644 --- a/gramps/gen/datehandler/_date_sk.py +++ b/gramps/gen/datehandler/_date_sk.py @@ -165,4 +165,6 @@ class DateDisplaySK(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('sk_SK', 'sk', 'SK', 'Slovak'), DateParserSK, DateDisplaySK) +register_datehandler( + ('sk_SK', 'sk', 'SK', 'Slovak', ('%d.%m.%Y',)), + DateParserSK, DateDisplaySK) diff --git a/gramps/gen/datehandler/_date_sl.py b/gramps/gen/datehandler/_date_sl.py index 4764d4ab8..553d15e5e 100644 --- a/gramps/gen/datehandler/_date_sl.py +++ b/gramps/gen/datehandler/_date_sl.py @@ -24,7 +24,7 @@ """ Slovenian-specific classes for parsing and displaying dates - new framework. """ -from __future__ import unicode_literals + #------------------------------------------------------------------------- # # Python modules @@ -121,6 +121,7 @@ class DateDisplaySL(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(("sl", "SL", "sl_SI", "slovenščina", "slovenian", "Slovenian", - "sl_SI.UTF8", "sl_SI.UTF-8", "sl_SI.utf-8", "sl_SI.utf8"), - DateParserSL, DateDisplaySL) +register_datehandler( + ("sl_SI", "sl", "SL", + "slovenščina", "slovenian", "Slovenian", ('%d. %m. %Y',)), + DateParserSL, DateDisplaySL) diff --git a/gramps/gen/datehandler/_date_sr.py b/gramps/gen/datehandler/_date_sr.py index 11cf16096..81e9aceb1 100644 --- a/gramps/gen/datehandler/_date_sr.py +++ b/gramps/gen/datehandler/_date_sr.py @@ -256,7 +256,7 @@ class DateDisplaySR_Base(DateDisplay): if date_val[0] == 0 and date_val[1] == 0: value = str(date_val[2]) else: - value = self._tformat.replace('%m', str(date_val[1])) + value = self.dhformat.replace('%m', str(date_val[1])) value = value.replace('%d', str(date_val[0])) value = value.replace('%Y', str(abs(date_val[2]))) #some locale magic already provides the right separator @@ -423,9 +423,11 @@ class DateDisplaySR_Cyrillic(DateDisplaySR_Base): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('srpski', 'Srpski', - 'sr_Latn', 'sr_Latn_RS', 'sr_RS@latin'), - DateParserSR, DateDisplaySR_Latin) -register_datehandler(('sr', 'српски', 'Српски', 'serbian', - 'sr_RS', 'sr_Cyrl', 'sr_Cyrl_RS'), - DateParserSR, DateDisplaySR_Cyrillic) +register_datehandler( + ('sr_RS.utf8@latin', 'srpski', 'Srpski', + 'sr_Latn', 'sr_Latn_RS', 'sr_RS@latin', ('%d.%m.%Y.',)), + DateParserSR, DateDisplaySR_Latin) +register_datehandler( + ('sr_RS', 'sr', 'sr_Cyrl', 'sr_Cyrl_RS', + 'српски', 'Српски', 'serbian', ('%d.%m.%Y.',)), + DateParserSR, DateDisplaySR_Cyrillic) diff --git a/gramps/gen/datehandler/_date_sv.py b/gramps/gen/datehandler/_date_sv.py index 0ff609604..63ccf0d42 100644 --- a/gramps/gen/datehandler/_date_sv.py +++ b/gramps/gen/datehandler/_date_sv.py @@ -181,4 +181,6 @@ class DateDisplaySv(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('sv_SE', 'sv_SE.UTF-8', 'sv', 'Swedish'), DateParserSv, DateDisplaySv) +register_datehandler( + ('sv_SE', 'sv_SE.UTF-8', 'sv', 'Swedish', ('%Y-%m-%d',)), + DateParserSv, DateDisplaySv) diff --git a/gramps/gen/datehandler/_date_uk.py b/gramps/gen/datehandler/_date_uk.py index ad0b1dcba..33eed34c1 100644 --- a/gramps/gen/datehandler/_date_uk.py +++ b/gramps/gen/datehandler/_date_uk.py @@ -138,5 +138,6 @@ class DateDisplayUK(DateDisplay): # Register classes # #------------------------------------------------------------------------- -register_datehandler(('uk_UA', 'uk', 'ukrainian', 'Ukrainian'), - DateParserUK, DateDisplayUK) +register_datehandler( + ('uk_UA', 'uk', 'ukrainian', 'Ukrainian', ('%d.%m.%Y',)), + DateParserUK, DateDisplayUK) diff --git a/gramps/gen/datehandler/_date_zh_CN.py b/gramps/gen/datehandler/_date_zh_CN.py index 248773910..df881134f 100644 --- a/gramps/gen/datehandler/_date_zh_CN.py +++ b/gramps/gen/datehandler/_date_zh_CN.py @@ -178,5 +178,6 @@ class DateDisplayZH_CN(DateDisplay): # #------------------------------------------------------------------------- -register_datehandler(('zh_CN', 'zh_SG', 'zh', 'chinese', 'Chinese'), - DateParserZH_CN, DateDisplayZH_CN) +register_datehandler( + ('zh_CN', 'zh_SG', 'zh', 'chinese', 'Chinese', ('%Y年%m月%d日',)), + DateParserZH_CN, DateDisplayZH_CN) diff --git a/gramps/gen/datehandler/_date_zh_TW.py b/gramps/gen/datehandler/_date_zh_TW.py index b2aee334d..3ff683ad5 100644 --- a/gramps/gen/datehandler/_date_zh_TW.py +++ b/gramps/gen/datehandler/_date_zh_TW.py @@ -178,5 +178,6 @@ class DateDisplayZH_TW(DateDisplay): # #------------------------------------------------------------------------- -register_datehandler(('zh_TW', 'zh_HK'), - DateParserZH_TW, DateDisplayZH_TW) +register_datehandler( + ('zh_TW', 'zh_HK', ('西元%Y年%m月%d日',)), + DateParserZH_TW, DateDisplayZH_TW) diff --git a/gramps/gen/datehandler/_datedisplay.py b/gramps/gen/datehandler/_datedisplay.py index 97ee360cc..94a2692f4 100644 --- a/gramps/gen/datehandler/_datedisplay.py +++ b/gramps/gen/datehandler/_datedisplay.py @@ -4,7 +4,7 @@ # # Copyright (C) 2004-2006 Donald N. Allingham # Copyright (C) 2013 Vassilii Khachaturov -# Copyright (C) 2014-2015 Paul Franklin +# Copyright (C) 2014-2017 Paul Franklin # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -26,6 +26,13 @@ U.S English date display class. Should serve as the base class for all localized tasks. """ +#------------------------------------------------------------------------- +# +# Python modules +# +#------------------------------------------------------------------------- +import datetime + #------------------------------------------------------------------------- # # set up logging @@ -40,7 +47,7 @@ log = logging.getLogger(".DateDisplay") # #------------------------------------------------------------------------- from ..lib.date import Date -from . import _grampslocale +from ..const import GRAMPS_LOCALE as glocale from ..utils.grampslocale import GrampsLocale from ._datestrings import DateStrings @@ -58,8 +65,6 @@ class DateDisplay: Base date display class. """ - _tformat = _grampslocale.tformat - formats = ( # format 0 - must always be ISO _T_("YYYY-MM-DD (ISO)"), @@ -98,7 +103,21 @@ class DateDisplay: _bce_str = "%s B.C.E." # this will be overridden if a locale-specific date displayer exists - def __init__(self, format=None): + def __init__(self, format=None, blocale=None): + """ + :param blocale: allow translation of dates and date formats + :type blocale: a :class:`.GrampsLocale` instance + """ + from ._datehandler import locale_tformat # circular import if above + if blocale: + self._locale = blocale + elif not hasattr(self, '_locale'): + self._locale = glocale + if self._locale.calendar in locale_tformat: + self.dhformat = locale_tformat[self._locale.calendar] # date format + else: + self.dhformat = locale_tformat['en_GB'] # something is required + self.formats_changed() # allow overriding so a subclass can modify self._ds = DateStrings(self._locale) calendar = list(self._ds.calendar) calendar[Date.CAL_GREGORIAN] = "" # that string only used in parsing, @@ -301,6 +320,10 @@ class DateDisplay: : _("calculated|{short_month} {year}"), } + def formats_changed(self): + """ Allow overriding so a subclass can modify """ + pass + def set_format(self, format): self.format = format @@ -332,6 +355,9 @@ class DateDisplay: Disregard any format settings and use display_iso for each date. (Will be overridden if a locale-specific date displayer exists.) + + (The usage is "displayer.display(...)" (or a variant, e.g. _dd.display) + so any subclass must have a "display" method, somehow, or use this.) """ mod = date.get_modifier() cal = date.get_calendar() @@ -540,6 +566,18 @@ class DateDisplay: return self.FORMATS_short_month_year[inflect].format( short_month = short_months[month], year = '').rstrip() + def _get_short_weekday(self, date_val): + if date_val[0] == 0 or date_val[1] == 0: # no day or no month or both + return '' + w_day = datetime.date(date_val[2], date_val[1], date_val[0]) # y, m, d + return self.short_days[((w_day.weekday() + 1) % 7) + 1] + + def _get_long_weekday(self, date_val): + if date_val[0] == 0 or date_val[1] == 0: # no day or no month or both + return '' + w_day = datetime.date(date_val[2], date_val[1], date_val[0]) # y, m, d + return self.long_days[((w_day.weekday() + 1) % 7) + 1] + def dd_dformat01(self, date_val): """ numerical @@ -553,9 +591,17 @@ class DateDisplay: if date_val[0] == date_val[1] == 0: return str(date_val[2]) else: - value = self._tformat.replace('%m', str(date_val[1])) + value = self.dhformat.replace('%m', str(date_val[1])) # some locales have %b for the month, e.g. ar_EG, is_IS, nb_NO + # so it would be "Jan" but as it's "numeric" I'll make it "1" value = value.replace('%b', str(date_val[1])) + # some locales have %B for the month, e.g. ta_IN + # so it would be "January" but as it's "numeric" I'll make it 1 + value = value.replace('%B', str(date_val[1])) + # some locales have %a for the abbreviated day, e.g. is_IS + value = value.replace('%a', self._get_short_weekday(date_val)) + # some locales have %A for the long/full day, e.g. ta_IN + value = value.replace('%A', self._get_long_weekday(date_val)) if date_val[0] == 0: # ignore the zero day and its delimiter i_day = value.find('%d') value = value.replace(value[i_day:i_day+3], '') @@ -719,17 +765,10 @@ class DateDisplayEn(DateDisplay): """ English language date display class. """ - - - def __init__(self, format=None): - """ - Create a DateDisplay class that converts a Date object to a string - of the desired format. The format value must correspond to the format - list value (DateDisplay.format[]). - """ - - DateDisplay.__init__(self, format) - display = DateDisplay.display_formatted - _locale = GrampsLocale(languages='en') # no register_datehandler here +class DateDisplayGB(DateDisplay): + """ + British-English language date display class (its format is different). + """ + display = DateDisplay.display_formatted diff --git a/gramps/gen/datehandler/_datehandler.py b/gramps/gen/datehandler/_datehandler.py index 8a8eeba21..9fafe9388 100644 --- a/gramps/gen/datehandler/_datehandler.py +++ b/gramps/gen/datehandler/_datehandler.py @@ -2,6 +2,7 @@ # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2004-2006 Donald N. Allingham +# Copyright (C) 2017 Paul Franklin # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -43,7 +44,7 @@ log = logging.getLogger(".gen.datehandler") # #------------------------------------------------------------------------- from ._dateparser import DateParser -from ._datedisplay import DateDisplay, DateDisplayEn +from ._datedisplay import DateDisplay, DateDisplayEn, DateDisplayGB from ..constfunc import win from ..const import GRAMPS_LOCALE as glocale from ..utils.grampslocale import GrampsLocale @@ -74,19 +75,36 @@ LANG_SHORT = str(LANG_SHORT) LANG_TO_PARSER = { 'C' : DateParser, - 'en' : DateParser, - 'English_United States' : DateParser, } LANG_TO_DISPLAY = { 'C' : DateDisplayEn, - 'en' : DateDisplayEn, - 'en_GB' : DateDisplayEn, - 'English_United States' : DateDisplayEn, 'ko_KR' : DateDisplay, - 'nb_NO' : DateDisplay, # TODO this's in _date_nb, why here? } +main_locale = { } # this will be augmented by calls to register_datehandler + +locale_tformat = {} # locale "tformat" (date format) strings + +for no_handler in ( + ('C', ('%d/%m/%Y',)), + ('eo_EO', 'eo', 'Esperanto', ('%d/%m/%Y',)), # 'eo_EO' is a placeholder + ('he_IL', 'he', 'Hebrew', ('%d/%m/%Y',)), + ('sq_AL', 'sq', 'Albanian', ('%Y/%b/%d',)), + ('tr_TR', 'tr', 'Turkish', ('%d/%m/%Y',)), + ('vi_VN', 'vi', 'Vietnamese', ('%d/%m/%Y',)), + ): + format_string = '' + for possible_format in no_handler: + if isinstance(possible_format, tuple): + format_string = possible_format[0] # pre-seeded date format string + # maintain legacy gramps transformations + format_string = format_string.replace('%y','%Y').replace('-', '/') + for lang_str in no_handler: + if isinstance(lang_str, tuple): continue + main_locale[lang_str] = no_handler[0] + locale_tformat[lang_str] = format_string # locale's date format string + def register_datehandler(locales,parse_class,display_class): """ Registers the passed date parser class and date displayer @@ -104,8 +122,25 @@ def register_datehandler(locales,parse_class,display_class): :param display_class: Class to be associated with displaying :type display_class: :class:`.DateDisplay` """ + format_string = '' + for possible_format in locales: # allow possibly embedding a date format + if isinstance(possible_format, tuple): + format_string = possible_format[0] # pre-seeded date format string + # maintain legacy gramps transformations + format_string = format_string.replace('%y','%Y').replace('-', '/') for lang_str in locales: + if isinstance(lang_str, tuple): continue LANG_TO_PARSER[lang_str] = parse_class LANG_TO_DISPLAY[lang_str] = display_class + main_locale[lang_str] = locales[0] + locale_tformat[lang_str] = format_string # locale's date format string parse_class._locale = display_class._locale = GrampsLocale(lang=locales[0]) + +register_datehandler( + ('en_GB', 'English_United Kingdom', ("%d/%m/%y",)), + DateParser, DateDisplayGB) + +register_datehandler( + ('en_US', 'en', 'English_United States', ("%m/%d/%y",)), + DateParser, DateDisplayEn) diff --git a/gramps/gen/datehandler/_dateparser.py b/gramps/gen/datehandler/_dateparser.py index 29c1518d3..ce6e54afc 100644 --- a/gramps/gen/datehandler/_dateparser.py +++ b/gramps/gen/datehandler/_dateparser.py @@ -3,6 +3,7 @@ # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2004-2006 Donald N. Allingham +# Copyright (C) 2017 Paul Franklin # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -46,7 +47,7 @@ log = logging.getLogger(".DateParser") # #------------------------------------------------------------------------- from ..lib.date import Date, DateError, Today -from . import _grampslocale +from ..const import GRAMPS_LOCALE as glocale from ..utils.grampslocale import GrampsLocale from ._datestrings import DateStrings @@ -192,10 +193,7 @@ class DateParser: converted, the text string is assigned. """ - _locale = GrampsLocale(lang='en', languages='en') - - fmt = _grampslocale.tformat - _fmt_parse = re.compile(".*%(\S).*%(\S).*%(\S).*") + _dhformat_parse = re.compile(".*%(\S).*%(\S).*%(\S).*") # RFC-2822 only uses capitalized English abbreviated names, no locales. _rfc_days = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat') @@ -315,7 +313,7 @@ class DateParser: return else: DateParser._langs.add(lang) - ds = DateStrings(self._locale) + ds = self._ds = DateStrings(self._locale) log.debug("Begin building parser prefix tables for {}".format(lang)) _build_prefix_table(DateParser.month_to_int, _generate_variants( @@ -332,7 +330,21 @@ class DateParser: _build_prefix_table(DateParser.calendar_to_int, _generate_variants(zip(ds.calendar))) - def __init__(self): + def __init__(self, plocale=None): + """ + :param plocale: allow correct date format to be loaded and parsed + :type plocale: a :class:`.GrampsLocale` instance + """ + from ._datehandler import locale_tformat # circular import if above + if plocale: + self._locale = plocale + elif not hasattr(self, '_locale'): + self._locale = glocale + if self._locale.calendar in locale_tformat: + self.dhformat = locale_tformat[self._locale.calendar] # date format + else: + self.dhformat = locale_tformat['en_GB'] # something is required + self.dhformat_changed() # Allow overriding so a subclass can modify it self.init_strings() self.parser = { Date.CAL_GREGORIAN : self._parse_gregorian, @@ -344,16 +356,24 @@ class DateParser: Date.CAL_SWEDISH : self._parse_swedish, } - match = self._fmt_parse.match(self.fmt.lower()) + match = self._dhformat_parse.match(self.dhformat.lower()) if match: - self.dmy = (match.groups() == ('d', 'm', 'y') or \ - match.groups() == ('d', 'b', 'y')) + self._ddmy = match.groups() == ('a', 'e', 'b', 'y') # Icelandic + self.dmy = (match.groups() == ('d', 'm', 'y') or + match.groups() == ('e', 'm', 'y') or # Bulgarian + match.groups() == ('d', 'b', 'y') or + match.groups() == ('a', 'e', 'b', 'y')) self.ymd = (match.groups() == ('y', 'm', 'd') or \ match.groups() == ('y', 'b', 'd')) # note ('m','d','y') is valid -- in which case both will be False else: self.dmy = True self.ymd = False + self._ddmy = False + + def dhformat_changed(self): + """ Allow overriding so a subclass can modify it """ + pass def re_longest_first(self, keys): """ @@ -371,7 +391,7 @@ class DateParser: Most of the re's in most languages can stay as is. span and range most likely will need to change. Whatever change is done, this method may be called first as DateParser.init_strings(self) so that the - invariant expresions don't need to be repeteadly coded. All differences + invariant expresions don't need to be repeatedly coded. All differences can be coded after DateParser.init_strings(self) call, that way they override stuff from this method. @@ -591,6 +611,7 @@ class DateParser: value = subparser(text) if value != Date.EMPTY: return value + match = self._iso.match(text) if match: groups = match.groups() @@ -633,6 +654,8 @@ class DateParser: groups = match.groups() if groups == (None, None, None, None, None): return Date.EMPTY + if self._ddmy: # Icelandic + groups = groups[1:] # ignore the day of the week at the start if self.ymd: # '1789' and ymd: incomplete date if groups[1] is None: diff --git a/gramps/gen/datehandler/_datestrings.py b/gramps/gen/datehandler/_datestrings.py index 1b05d3920..b8b4187e6 100644 --- a/gramps/gen/datehandler/_datestrings.py +++ b/gramps/gen/datehandler/_datestrings.py @@ -270,7 +270,7 @@ if __name__ == '__main__': import gettext lang = glocale.lang lang_short = lang[:2] - available_langs = glocale.get_available_translations() + available_langs = glocale.languages # get the cached list if glocale.check_available_translations(lang) is None: print ("Translation for current language {lang} not available.\n" "Available translations: {list}.\n" diff --git a/gramps/gen/datehandler/_dateutils.py b/gramps/gen/datehandler/_dateutils.py index bfbd92562..8e38ed2f8 100644 --- a/gramps/gen/datehandler/_dateutils.py +++ b/gramps/gen/datehandler/_dateutils.py @@ -55,10 +55,10 @@ def get_date_formats(flocale=glocale): trans_text = flocale.translation.sgettext try: return tuple(trans_text(fmt) - for fmt in LANG_TO_DISPLAY[flocale.lang].formats) + for fmt in LANG_TO_DISPLAY[flocale.lang](0).formats) except: return tuple(trans_text(fmt) - for fmt in LANG_TO_DISPLAY['C'].formats) + for fmt in LANG_TO_DISPLAY['C'](0).formats) def set_format(value): try: diff --git a/gramps/gen/datehandler/_grampslocale.py b/gramps/gen/datehandler/_grampslocale.py index df59a2883..724322b55 100644 --- a/gramps/gen/datehandler/_grampslocale.py +++ b/gramps/gen/datehandler/_grampslocale.py @@ -20,8 +20,19 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # +#------------------------------------------------------------------------- +# +# Python modules +# +#------------------------------------------------------------------------- import locale -from ..const import GRAMPS_LOCALE as glocale + +#------------------------------------------------------------------------- +# +# Gramps modules +# +#------------------------------------------------------------------------- +from ..const import GRAMPS_LOCALE as glocale # TODO unneeded? (see codeset) """ Some OS environments do not support the locale.nl_langinfo() method @@ -33,7 +44,7 @@ strftime. Since these routines return values encoded into selected character set, we have to convert to unicode. """ -codeset = glocale.encoding +codeset = glocale.encoding # TODO I don't think "codeset" is used anymore try: @@ -89,20 +100,15 @@ try: _deprecated_short_days = ( "", - locale.nl_langinfo(locale.ABDAY_1), # Sunday - locale.nl_langinfo(locale.ABDAY_2), # Monday - locale.nl_langinfo(locale.ABDAY_3), # Tuesday - locale.nl_langinfo(locale.ABDAY_4), # Wednesday - locale.nl_langinfo(locale.ABDAY_5), # Thursday - locale.nl_langinfo(locale.ABDAY_6), # Friday - locale.nl_langinfo(locale.ABDAY_7), # Saturday + locale.nl_langinfo(locale.ABDAY_1), # Sun + locale.nl_langinfo(locale.ABDAY_2), # Mon + locale.nl_langinfo(locale.ABDAY_3), # Tue + locale.nl_langinfo(locale.ABDAY_4), # Wed + locale.nl_langinfo(locale.ABDAY_5), # Thu + locale.nl_langinfo(locale.ABDAY_6), # Fri + locale.nl_langinfo(locale.ABDAY_7), # Sat ) - tformat = locale.nl_langinfo(locale.D_FMT).replace('%y','%Y') - # Gramps treats dates with '-' as ISO format, so replace separator on - # locale dates that use '-' to prevent confict - tformat = tformat.replace('-', '/') - except: import time @@ -160,37 +166,11 @@ except: _deprecated_short_days = ( "", - time.strftime('%a',(1,1,1,1,1,1,6,1,1)), # Sunday - time.strftime('%a',(1,1,1,1,1,1,0,1,1)), # Monday - time.strftime('%a',(1,1,1,1,1,1,1,1,1)), # Tuesday - time.strftime('%a',(1,1,1,1,1,1,2,1,1)), # Wednesday - time.strftime('%a',(1,1,1,1,1,1,3,1,1)), # Thursday - time.strftime('%a',(1,1,1,1,1,1,4,1,1)), # Friday - time.strftime('%a',(1,1,1,1,1,1,5,1,1)), # Saturday + time.strftime('%a',(1,1,1,1,1,1,6,1,1)), # Sun + time.strftime('%a',(1,1,1,1,1,1,0,1,1)), # Mon + time.strftime('%a',(1,1,1,1,1,1,1,1,1)), # Tue + time.strftime('%a',(1,1,1,1,1,1,2,1,1)), # Wed + time.strftime('%a',(1,1,1,1,1,1,3,1,1)), # Thu + time.strftime('%a',(1,1,1,1,1,1,4,1,1)), # Fri + time.strftime('%a',(1,1,1,1,1,1,5,1,1)), # Sat ) - - # depending on the locale, the value returned for 20th Feb 2009 could be - # of the format '20/2/2009', '20/02/2009', '20.2.2009', '20.02.2009', - # '20-2-2009', '20-02-2009', '2009/02/20', '2009.02.20', '2009-02-20', - # '09-02-20' hence to reduce the possible values to test, make sure month - # is double digit also day should be double digit, preferably greater than - # 12 for human readablity - - timestr = time.strftime('%x',(2005,10,25,1,1,1,1,1,1)) - - # Gramps treats dates with '-' as ISO format, so replace separator on - # locale dates that use '-' to prevent confict - timestr = timestr.replace('-', '/') - time2fmt_map = { - '25/10/2005' : '%d/%m/%Y', - '10/25/2005' : '%m/%d/%Y', - '2005/10/25' : '%Y/%m/%d', - '25.10.2005' : '%d.%m.%Y', - '10.25.2005' : '%m.%d.%Y', - '2005.10.25' : '%Y.%m.%d', - } - - try: - tformat = time2fmt_map[timestr] - except KeyError as e: - tformat = '%d/%m/%Y' #default value diff --git a/gramps/gen/plug/report/_reportbase.py b/gramps/gen/plug/report/_reportbase.py index 239d72605..b0b59129b 100644 --- a/gramps/gen/plug/report/_reportbase.py +++ b/gramps/gen/plug/report/_reportbase.py @@ -26,6 +26,7 @@ # Gramps modules # #------------------------------------------------------------------------- +from ...const import GRAMPS_LOCALE as glocale from ...utils.grampslocale import GrampsLocale from ...display.name import NameDisplay from ...config import config @@ -67,9 +68,15 @@ class Report: Set the translator to one selected with stdoptions.add_localization_option(). """ + from ...datehandler import LANG_TO_DISPLAY, main_locale if language == GrampsLocale.DEFAULT_TRANSLATION_STR: language = None - locale = GrampsLocale(lang=language) + if language is None: # the UI language + locale = glocale + elif language in LANG_TO_DISPLAY: # a displayer exists + locale = LANG_TO_DISPLAY[main_locale[language]]._locale + else: # no displayer + locale = GrampsLocale(lang=language) self._ = locale.translation.sgettext self._get_date = locale.get_date self._get_type = locale.get_type diff --git a/gramps/gen/utils/grampslocale.py b/gramps/gen/utils/grampslocale.py index 725409b1d..485ea5bdd 100644 --- a/gramps/gen/utils/grampslocale.py +++ b/gramps/gen/utils/grampslocale.py @@ -4,6 +4,7 @@ # # Copyright (C) 2000-2006 Donald N. Allingham # Copyright (C) 2009 Brian G. Matherly +# Copyright (C) 2013 John Ralls # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -140,6 +141,46 @@ def _check_mswin_locale_reverse(locale): return ('en_GB', '1252') return (None, None) +def _check_gformat(): + """ + Some OS environments do not support the locale.nl_langinfo() method + of determing month names and other date related information. + """ + try: + gformat = locale.nl_langinfo(locale.D_FMT).replace('%y','%Y') + # Gramps treats dates with '-' as ISO format, so replace separator + # on locale dates that use '-' to prevent confict + gformat = gformat.replace('-', '/') + except: + ''' + Depending on the locale, the value returned for 20th Feb 2009 + could be '20/2/2009', '20/02/2009', '20.2.2009', '20.02.2009', + '20-2-2009', '20-02-2009', '2009/02/20', '2009.02.20', + '2009-02-20', or '09-02-20' so to reduce the possible values to + test for, make sure both the month and the day are double digits, + preferably greater than 12 for human readablity + ''' + import time + timestr = time.strftime('%x',(2005,10,25,1,1,1,1,1,1)) + + # Gramps treats dates with '-' as ISO format, so replace separator + # on locale dates that use '-' to prevent confict + timestr = timestr.replace('-', '/') + + time2fmt_map = {'25/10/2005' : '%d/%m/%Y', + '10/25/2005' : '%m/%d/%Y', + '2005/10/25' : '%Y/%m/%d', + '25.10.2005' : '%d.%m.%Y', + '10.25.2005' : '%m.%d.%Y', + '2005.10.25' : '%Y.%m.%d', + } + + try: + gformat = time2fmt_map[timestr] + except KeyError: + gformat = '%d/%m/%Y' # default value + return gformat + #------------------------------------------------------------------------ # # GrampsLocale Class @@ -331,18 +372,6 @@ class GrampsLocale: else: LOG.debug("No translation for LC_MESSAGES locale %s", loc) - # $LANGUAGE overrides $LANG, $LC_MESSAGES - if "LANGUAGE" in os.environ: - language = [x for x in [self.check_available_translations(l) - for l in os.environ["LANGUAGE"].split(":")] - if x] - if language: - self.language = language - if not self.lang.startswith(self.language[0]): - LOG.debug("Overiding locale setting %s with LANGUAGE setting %s", self.lang, self.language[0]) - elif _failure: - LOG.warning("No valid locale settings found, using US English") - if HAVE_ICU: self.calendar = locale.getlocale(locale.LC_TIME)[0] or self.lang[:5] self.collation = locale.getlocale(locale.LC_COLLATE)[0] or self.lang[:5] @@ -374,6 +403,23 @@ class GrampsLocale: else: self.currency = self.lang + # $LANGUAGE overrides $LANG, $LC_MESSAGES + if "LANGUAGE" in os.environ: + language = [x for x in [self.check_available_translations(l) + for l in os.environ["LANGUAGE"].split(":")] + if x] + if language: + self.language = language + if not self.lang.startswith(self.language[0]): + LOG.debug("Overiding locale setting '%s' with LANGUAGE setting '%s'", self.lang, self.language[0]) + self.lang = self.calendar = self.language[0] + elif _failure: + LOG.warning("No valid locale settings found, using US English") + + if __debug__: + LOG.debug("The locale tformat for '%s' is '%s'", + self.lang, _check_gformat()) + def _win_bindtextdomain(self, localedomain, localedir): """ Help routine for loading and setting up libintl attributes @@ -486,12 +532,15 @@ class GrampsLocale: an alternate localization to the one used for the UI; for example, some reports offer the option to use a different language. + + This GrampsLocale class does no caching of the secondary locale. + If any caching is desired it must be done externally. """ if not self.localedir: LOG.warning("No Localedir provided, unable to find translations") if not self.localedomain: - if _firstlocaledomain: + if _firstlocaledomain: # TODO this variable is nowhere else self.localedomain = _first.localedomain else: self.localedomain = "gramps" @@ -509,7 +558,8 @@ class GrampsLocale: if not self.language and _first.language: self.language = _first.language - self.calendar = self.collation = self.lang + self.numeric = self.currency = self.calendar = self.collation = self.lang + def __init__(self, localedir=None, lang=None, domain=None, languages=None): """ @@ -668,11 +718,11 @@ class GrampsLocale: elif self.calendar[:2] in displayers: self._dd = displayers[self.calendar[:2]](val) elif self != _first and _first.calendar in displayers: - self._dd = displayers[_first.calendar](val) + self._dd = displayers[_first.calendar](val, blocale=self) elif self != _first and _first.calendar[:2] in displayers: - self._dd = displayers[_first.calendar[:2]](val) + self._dd = displayers[_first.calendar[:2]](val, blocale=self) else: - self._dd = displayers['C'](val) + self._dd = displayers['C'](val, blocale=self) return self._dd diff --git a/gramps/plugins/lib/libgedcom.py b/gramps/plugins/lib/libgedcom.py index b75fe0358..06367bcbc 100644 --- a/gramps/plugins/lib/libgedcom.py +++ b/gramps/plugins/lib/libgedcom.py @@ -135,6 +135,7 @@ from gramps.gen.lib.const import IDENTICAL, DIFFERENT from gramps.gen.lib import (StyledText, StyledTextTag, StyledTextTagType) from gramps.plugins.lib.libplaceimport import PlaceImport from gramps.gen.display.place import displayer as _pd +from gramps.gen.utils.grampslocale import GrampsLocale #------------------------------------------------------------------------- # @@ -729,7 +730,13 @@ class GedcomDateParser(DateParser): 'may' : 5, 'jun' : 6, 'jul' : 7, 'aug' : 8, 'sep' : 9, 'oct' : 10, 'nov' : 11, 'dec' : 12, } - fmt = "%m/%d/%y" + + _locale = GrampsLocale(lang='en_US') # no register_datehandler here + + def dhformat_changed(self): + """ Allow overriding so a subclass can modify it """ + self.dhformat = "%m/%d/%y" + #------------------------------------------------------------------------- #