From ee396b27f6e38dbc522ba9b23ff5887376ea60ea Mon Sep 17 00:00:00 2001
From: David MENTRE
Date: Sat, 19 Dec 2009 20:23:30 +0100
Subject: [PATCH 4/5] Put language specific code into separate objects into i18n module
* Follow d2 recommendations and implement a suitable object hierachy
that stores the code specific to a given language.
* Provide an object for fr_FR language.
* Update street_index.py to use those objects.
---
ocitysmap/i18n.py | 102 +++++++++++++++++++++++++++-----------------
ocitysmap/street_index.py | 28 +++++++-----
2 files changed, 78 insertions(+), 52 deletions(-)
diff --git a/ocitysmap/i18n.py b/ocitysmap/i18n.py
index 7e95514..46aa138 100644
--- a/ocitysmap/i18n.py
+++ b/ocitysmap/i18n.py
@@ -23,43 +23,65 @@
import re
-APPELLATIONS = [ u"Allée", u"Avenue", u"Boulevard", u"Carrefour", u"Chaussée",
- u"Chemin", u"Cité", u"Clos", u"Côte", u"Cour", u"Cours",
- u"Degré",
- u"Esplanade", u"Impasse", u"Liaison", u"Mail", u"Montée",
- u"Passage", u"Place", u"Placette", u"Pont", u"Promenade",
- u"Quai",
- u"Résidence", u"Rond-Point", u"Rang", u"Route", u"Rue",
- u"Ruelle",
- u"Square", u"Traboule", u"Traverse", u"Venelle", u"Villa",
- u"Voie", u"Rond-point" ]
-DETERMINANTS = [ u" des", u" du", u" de la", u" de l'", u" de", u" d'", u"" ]
-
-SPACE_REDUCE = re.compile(r"\s+")
-PREFIX_REGEXP = re.compile(r"^(?P(%s)(%s)?)\s?\b(?P.*)" %
- ("|".join(APPELLATIONS),
- "|".join(DETERMINANTS)), re.IGNORECASE | re.UNICODE)
-
-# for IndexPageGenerator._upper_unaccent_string
-E_ACCENT = re.compile(ur"[éèêëẽ]", re.IGNORECASE | re.UNICODE)
-I_ACCENT = re.compile(ur"[Ãìîïĩ]", re.IGNORECASE | re.UNICODE)
-A_ACCENT = re.compile(ur"[áà âäã]", re.IGNORECASE | re.UNICODE)
-O_ACCENT = re.compile(ur"[óòôöõ]", re.IGNORECASE | re.UNICODE)
-U_ACCENT = re.compile(ur"[úùûüũ]", re.IGNORECASE | re.UNICODE)
-
-def user_readable_street(name):
- name = name.strip()
- name = SPACE_REDUCE.sub(" ", name)
- name = PREFIX_REGEXP.sub(r"\g (\g)", name)
- return name
-
-def _upper_unaccent_string(s):
- s = E_ACCENT.sub("e", s)
- s = I_ACCENT.sub("i", s)
- s = A_ACCENT.sub("a", s)
- s = O_ACCENT.sub("o", s)
- s = U_ACCENT.sub("u", s)
- return s.upper()
-
-def first_letter_equal(a, b):
- return _upper_unaccent_string(a) == _upper_unaccent_string(b)
+class i18n:
+ """Functions needed to be implemented for a new language.
+ See i18n_fr_FR_UTF8 below for an example. """
+ def language_code(self):
+ pass
+
+ def user_readable_street(self, name):
+ pass
+
+ def first_letter_equal(self, a, b):
+ pass
+
+class i18n_fr_FR_UTF8(i18n):
+ APPELLATIONS = [ u"Allée", u"Avenue", u"Boulevard", u"Carrefour", u"Chaussée",
+ u"Chemin", u"Cité", u"Clos", u"Côte", u"Cour", u"Cours",
+ u"Degré",
+ u"Esplanade", u"Impasse", u"Liaison", u"Mail", u"Montée",
+ u"Passage", u"Place", u"Placette", u"Pont", u"Promenade",
+ u"Quai",
+ u"Résidence", u"Rond-Point", u"Rang", u"Route", u"Rue",
+ u"Ruelle",
+ u"Square", u"Traboule", u"Traverse", u"Venelle", u"Villa",
+ u"Voie", u"Rond-point" ]
+ DETERMINANTS = [ u" des", u" du", u" de la", u" de l'",
+ u" de", u" d'", u"" ]
+
+ SPACE_REDUCE = re.compile(r"\s+")
+ PREFIX_REGEXP = re.compile(r"^(?P(%s)(%s)?)\s?\b(?P.*)" %
+ ("|".join(APPELLATIONS),
+ "|".join(DETERMINANTS)), re.IGNORECASE
+ | re.UNICODE)
+
+ # for IndexPageGenerator._upper_unaccent_string
+ E_ACCENT = re.compile(ur"[éèêëẽ]", re.IGNORECASE | re.UNICODE)
+ I_ACCENT = re.compile(ur"[Ãìîïĩ]", re.IGNORECASE | re.UNICODE)
+ A_ACCENT = re.compile(ur"[áà âäã]", re.IGNORECASE | re.UNICODE)
+ O_ACCENT = re.compile(ur"[óòôöõ]", re.IGNORECASE | re.UNICODE)
+ U_ACCENT = re.compile(ur"[úùûüũ]", re.IGNORECASE | re.UNICODE)
+
+ def _upper_unaccent_string(self, s):
+ s = self.E_ACCENT.sub("e", s)
+ s = self.I_ACCENT.sub("i", s)
+ s = self.A_ACCENT.sub("a", s)
+ s = self.O_ACCENT.sub("o", s)
+ s = self.U_ACCENT.sub("u", s)
+ return s.upper()
+
+ def language_code(self):
+ return "fr_FR.UTF8"
+
+ def user_readable_street(self, name):
+ name = name.strip()
+ name = self.SPACE_REDUCE.sub(" ", name)
+ name = self.PREFIX_REGEXP.sub(r"\g (\g)", name)
+ return name
+
+ def first_letter_equal(self, a, b):
+ return self._upper_unaccent_string(a) == self._upper_unaccent_string(b)
+
+# The global map used by module users
+language_map = { 'fr_FR.UTF-8': i18n_fr_FR_UTF8() }
+
diff --git a/ocitysmap/street_index.py b/ocitysmap/street_index.py
index 0f859f5..fc47a95 100644
--- a/ocitysmap/street_index.py
+++ b/ocitysmap/street_index.py
@@ -39,9 +39,9 @@ class BaseOCitySMapError(Exception):
class UnsufficientDataError(BaseOCitySMapError):
"""Not enough data in the OSM database to proceed."""
-def _humanize_street_label(street):
+def _user_readable_label(street):
"""Creates a street label usable in the street list adjacent to the map
- (like 'Bréhat (Allée des)' from the street definition tuple."""
+ from the street definition tuple."""
def couple_compare(x,y):
a = y[0] - x[0]
@@ -52,7 +52,6 @@ def _humanize_street_label(street):
def distance(a,b):
return (b[0]-a[0])**2 + (b[1]-a[1])**2
- name = i18n.user_readable_street(street[0])
squares = street[1]
minx = min([x[0] for x in squares])
maxx = max([x[0] for x in squares])
@@ -89,11 +88,12 @@ def _humanize_street_label(street):
utils.gen_horizontal_square_label(first[1]),
utils.gen_vertical_square_label(last[0]),
utils.gen_horizontal_square_label(last[1]))
- return (name, label)
+ return label
class IndexPageGenerator:
- def __init__(self, streets):
+ def __init__(self, streets, i18n):
self.streets = streets
+ self.i18n = i18n
def _get_font_parameters(self, cr, fontsize):
cr.select_font_face("DejaVu", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
@@ -124,7 +124,7 @@ class IndexPageGenerator:
prevletter = u''
heading_letter_count = 0
for street in self.streets:
- if not i18n.first_letter_equal(street[0][0], prevletter):
+ if not self.i18n.first_letter_equal(street[0][0], prevletter):
heading_letter_count += 1
prevletter = street[0][0]
@@ -178,7 +178,7 @@ class IndexPageGenerator:
for street in self.streets:
# Letter label
firstletter = street[0][0]
- if not i18n.first_letter_equal(firstletter, prevletter):
+ if not self.i18n.first_letter_equal(firstletter, prevletter):
# Make sure we have no orphelin heading letter label at the
# end of a column
if y + heading_fheight + fheight > paperheight:
@@ -244,9 +244,8 @@ class OCitySMap:
assert bool(city_name) ^ bool(boundingbox)
(self.city_name, self.boundingbox) = (city_name, boundingbox)
- assert language is not None, "Language parameter is mandatory"
- self.language = language
- l.info('Language ' + self.language)
+ self.i18n = i18n.language_map[language]
+ l.info('Language ' + self.i18n.language_code())
if self.city_name:
l.info('OCitySMap renderer for %s.' % self.city_name)
@@ -471,7 +470,12 @@ class OCitySMap:
# built to represent the list of squares, and the list is
# alphabetically-sorted.
prev_locale = locale.getlocale(locale.LC_COLLATE)
- locale.setlocale(locale.LC_COLLATE, self.language)
+ locale.setlocale(locale.LC_COLLATE, self.i18n.language_code())
+
+ def _humanize_street_label(street):
+ return (self.i18n.user_readable_street(street[0]),
+ _user_readable_label(street))
+
try:
sl = sorted(map(_humanize_street_label, sl),
lambda x, y: locale.strcoll(x[0].lower(), y[0].lower()))
@@ -489,7 +493,7 @@ class OCitySMap:
output_filename = "%s_index.%s" % (output_prefix, file_type)
l.debug("rendering " + output_filename + "...")
- generator = IndexPageGenerator(self.streets)
+ generator = IndexPageGenerator(self.streets, self.i18n)
if file_type == 'xml':
l.debug('not rendering index as xml (not supported)')
--
1.6.3.3