Changeset 3290

Show
Ignore:
Timestamp:
07/28/2007 01:46:09 AM (1 year ago)
Author:
paul
Message:

I was reading up on Python's gettext module, trying to get
my head around why the accented characters in the es file
aren't translating correctly (turns out it is something to
do with how the original .po file was constructed where
codes like <92> were embedded in the file instead of the
encoded unicode bytes).

Anyway, I rewrote dLocalize.py to be more idiomatic python
and to greatly simplify it. Now, the base Dabo init.py
sets up Dabo's translation service, and dApp.py sets up
any user app translations (before, dLocalize did that
implicitly). Additionally, the developer can do it manually
by calling dLocalize.install() or even by using the gettext
module directly, if they so desire.

The major change with this is that we don't try to set
default language or charset: we merely pass that task off
to gettext which, if I understand correctly, will do the
right thing. If people need to set their locale's manually,
they just need to do it before the first 'import dabo'
in their app. Ex:

import locale
locale.setlocale(locale.LC_ALL, ("en", "utf-8"))

Key files changed in this:

dabo/dLocalize.py (major rewrite)
dabo/init.py (install localization for Dabo)
dabo/dApp.py (auto-install user app's localization)

All other files changed were merely to remove the import
lines ('from dLocalize import _').

You'll likely get DeprecationWarnings? when running your
existing applications, asking you to please remove the
'import _' lines. Note to self: remove those from the
AppWizard? spec files.

Tested on Linux. Will test and refine if needed on Windows
and Mac tomorrow.

Ed, Nizamov, and other interested parties: I'd appreciate
any feedback on the decisions I made here. I think it is
better this way, but if you don't think so, be heard!
:)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/dabo/__init__.py

    r3199 r3290  
    122122dAppRef = None 
    123123 
     124# Install localization service for dabo. dApp will install localization service 
     125# for the user application separately. 
     126import dLocalize 
     127dLocalize.install("dabo") 
     128 
     129 
    124130# Instantiate the logger object, which will send messages to user-overridable 
    125131# locations. Do this before any other imports. 
  • trunk/dabo/biz/dAutoBizobj.py

    r3054 r3290  
    22import datetime 
    33import dabo 
    4 from dabo.dLocalize import _ 
    54import dabo.dException as dException 
    65from dabo.biz.dBizobj import dBizobj 
  • trunk/dabo/biz/dBizobj.py

    r3272 r3290  
    55import dabo.dConstants as kons 
    66from dabo.db.dCursorMixin import dCursorMixin 
    7 from dabo.dLocalize import _ 
    87import dabo.dException as dException 
    98from dabo.dObject import dObject 
  • trunk/dabo/dApp.py

    r3269 r3290  
    1414import dabo.ui 
    1515import dabo.db 
     16import dLocalize 
    1617from dabo.lib.connParser import importConnections 
     18from dabo import dLocalize 
    1719import dSecurityManager 
    18 from dLocalize import _ 
    1920from dabo.lib.SimpleCrypt import SimpleCrypt 
    2021from dabo.dObject import dObject 
     
    221222        initAppInfo("appVersion", "") 
    222223        initAppInfo("vendorName", "") 
     224 
     225        # If there's a locale directory for the app and it looks valid, install it: 
     226        localeDir = os.path.join(self.HomeDirectory, "locale") 
     227        localeDomain = self.getAppInfo("appShortName").replace(" ", "_").lower() 
     228        if os.path.isdir(localeDir) and dLocalize.isValidDomain(localeDomain, localeDir): 
     229            lang = getattr(self, "_language", None) 
     230            charset = getattr(self, "_charset", None) 
     231            dLocalize.install(localeDomain, localeDir) 
     232            dLocalize.setLanguage(lang, charset) 
    223233 
    224234        self._initDB() 
     
    703713        will be raised. You may optionally pass a character set to use. 
    704714        """ 
    705         dabo.dLocalize.setLanguage(lang, charset) 
     715        self._language, self._charset = lang, charset 
     716        dLocalize.setLanguage(lang, charset) 
    706717 
    707718         
  • trunk/dabo/dEvents.py

    r3281 r3290  
    44from dabo.dObject import dObject 
    55import dabo.ui as ui 
    6 from dabo.dLocalize import _ 
    76 
    87 
  • trunk/dabo/dLocalize.py

    r3289 r3290  
    11# -*- coding: utf-8 -*- 
    2  
    3 import sys 
    4 import locale 
    5  
    6 # Do this up here, because we may be changing sys.getdefaultencoding: 
    7 defLang, defCharset = locale.getlocale()  ## need to respect this, if set, IIUC 
    8 if defLang is None: 
    9     defLang = locale.getdefaultlocale()[0] 
    10     if defLang is None: 
    11         defLang = "en" 
    12  
    13 if defCharset is None: 
    14     defCharset = sys.getfilesystemencoding() 
    15     if defCharset is None: 
    16         defCharset = "utf-8" 
    17  
    18 reload(sys) 
    19 sys.setdefaultencoding(defCharset) 
    20  
    212import os 
    223import gettext 
     4import locale 
     5import warnings 
    236import dabo 
    247 
     8_domains = {} 
    259 
    26 _appInitialized = False 
    27 _appHasLocale = False 
    28 _daboTranslate = None 
    29 _appTranslate = None 
    30 _localeDir = "locale" 
    31 _frozenLocaleDir = "dabo.locale" 
    32  
    33 languageAliases = {"english": "en", 
     10_languageAliases = {"english": "en", 
    3411        "spanish": "es", "espanol": "es", "español": "es", 
    3512        "french": "fr", "francais": "fr", "français": "fr",  
     
    3916        "russian": "ru"} 
    4017 
    41 def _(s): 
    42     """Translate the passed string into the current language, if possible.    
    4318 
    44     Dabo provides translations of common strings into several languages. If a  
    45     translation is found for the passed string, it will be returned. Otherwise, 
    46     the identical string will be returned. 
     19def install(domain="dabo", localedir=None, unicode_mo=True): 
     20    """Install the gettext translation service for the passed domain. 
    4721 
    48     In addition, user applications can define their own translations, in which 
    49     case we'll first look for translations in the application's locale directory, 
    50     and then fall back on Dabo's translations. 
    51   
    52     Localization files of app should be in under its locale directory, with the .mo 
    53     file's named after the application's short name. The default application name 
    54     is "daboapplication", so by default the app's .mo files should be named 
    55     "daboapplication.mo".  
     22    Either Dabo will be the only domain, or Dabo will be the fallback for a  
     23  different domain that the user's application set up. 
    5624    """ 
    57     global defLang, _appInitialized, _appHasLocale 
    58      
    59     if not _appInitialized: 
    60         try: 
    61             app = dabo.dAppRef 
    62         except AttributeError: 
    63             app = None 
    64              
    65         if app: 
    66             _appInitialized = True 
    67             # If appShortName not changed in user app, defaults to "daboapplication" 
    68             appName = app.getAppInfo("appShortName") 
    69             if appName is not None: 
    70                 _appHasLocale = setLanguage(domain=appName.lower().replace(" ", "_"), 
    71                         localedir=os.path.join(app.HomeDirectory, _localeDir)) 
     25    global _domains 
     26 
     27    if localedir is None: 
     28        if domain != "dabo": 
     29            raise ValueError, "Must send your application's localedir explicitly." 
     30        localedir = getDaboLocaleDir() 
     31    _domains[domain] = localedir 
     32    gettext.install(domain, localedir, unicode=unicode_mo) 
     33    setLanguage() 
    7234 
    7335 
    74     # Always return Unicode strings 
    75     if _appInitialized and _appHasLocale: 
    76         # Use app's localization, with Dabo's as a fallback: 
    77         return _appTranslate.ugettext(s) 
    78     else: 
    79         # App's localization is not in place; use only Dabo's: 
    80         return _daboTranslate.ugettext(s) 
    81          
     36def isValidDomain(domain, localedir): 
     37    """Return True if the localedir appears to contain translations for the domain.""" 
     38    return bool(gettext.find(domain, localedir, all=True)) 
     39 
     40 
     41def setLanguage(lang=None, charset=None): 
     42    """Change the language that strings get translated to, for all installed domains.""" 
     43    global _domains 
     44 
     45    lang = _languageAliases.get(lang, lang) 
     46 
     47    if lang is not None and isinstance(lang, basestring): 
     48        lang = [lang] 
     49 
     50    daboTranslation = None 
     51    daboLocaleDir = _domains.get("dabo", None) 
     52    if daboLocaleDir: 
     53        daboTranslation = gettext.translation("dabo", daboLocaleDir, languages=lang, codeset=charset) 
     54        daboTranslation.install() 
     55 
     56    for domain, localedir in _domains.items(): 
     57        if domain == "dabo": 
     58            continue  ## already handled separately above 
     59        try: 
     60            translation = gettext.translation(domain, localedir, languages=lang, codeset=charset) 
     61        except IOError: 
     62            raise IOError, "No translation found for domain '%s' and language %s." % (domain, lang) 
     63        if daboTranslation: 
     64            translation.add_fallback(daboTranslation) 
     65        translation.install() 
     66 
     67 
     68def getDaboLocaleDir(): 
     69    localedir = os.path.join(os.path.split(dabo.__file__)[0], "locale") 
     70    if not os.path.isdir(localedir): 
     71        # Frozen app? 
     72        # First need to find the directory that contains the .exe: 
     73        startupDir = localeDir 
     74        while startupDir: 
     75            startupDir = os.path.split(startupDir)[0] 
     76            if os.path.isdir(startupDir): 
     77                break 
     78        localedir = os.path.join(startupDir, "dabo.locale") 
     79    return localedir 
     80 
     81 
     82# All kinds of user apps (think appwizard) have the deprecated import of _: 
     83def _(s): 
     84    warnings.warn("Please remove your 'from dLocalize import _' statement.", DeprecationWarning, stacklevel=2) 
     85    __builtins__["_"](s) 
    8286 
    8387def n_(s): 
    84     """ Use it if you want to tell translation service about string 
    85     but don't want to translate it inplace. 
    86     """ 
    87     return s 
    88     #TODO: wouldn't it be better, if we will use something like _("string",False) in _ function ???  
    89     # i.e. one more argument for _function, telling by default to translate strings ? 
    90     # def _(s, translate=True): 
    91     #  pkm: Agree. Actually, can someone give an example of when you'd even want this? 
    92     #      Do we use it even? 
     88    warnings.warn("Please remove your 'from dLocalize import n_' statement.", DeprecationWarning, stacklevel=2) 
     89    __builtins__["_"](s) 
    9390 
    9491 
    95 def setLanguage(lang=None, charset=None, domain="dabo", localedir=None): 
    96     """Use it if you want to switch to another localizations than your default. 
    97     You should call it twice - once for dabo framework, and once for app. 
    98     """ 
    99     global defLang, defCharset, _daboTranslate, _appTranslate 
    100      
    101     #TODO: we should search system localizations directory as well 
    102  
    103     if localedir is None: 
    104         localedir = os.path.join(os.path.split(dabo.__file__)[0], _localeDir) 
    105         if not os.path.exists(localedir): 
    106             # Frozen app? 
    107             # First need to find the directory that contains the .exe: 
    108             startupDir = localeDir 
    109             while startupDir: 
    110                 startupDir = os.path.split(startupDir)[0] 
    111                 if os.path.isdir(startupDir): 
    112                     break 
    113             if domain == "dabo": 
    114                 frozenLocaleDir = _frozenLocaleDir 
    115             else: 
    116                 frozenLocaleDir = _localeDir 
    117             localedir = os.path.join(startupDir, frozenLocaleDir) 
    118  
    119     if charset is None: 
    120         charset = defCharset 
    121  
    122     if lang is None: 
    123         lang = defLang 
    124     else: 
    125         lang = lang.lower() 
    126         # It might be the full name instead of the two-letter abbreviation: 
    127         lang = languageAliases.get(lang, lang) 
    128          
    129     localefile = gettext.find(domain, localedir, languages=[lang], all=True) 
    130  
    131     if domain == "dabo": 
    132         if not localefile: 
    133             raise IOError, "No translation files found for Dabo. Looked in %s." % localedir 
    134         _daboTranslate = gettext.translation(domain, localedir, languages=[lang], codeset=charset) 
    135         defLang = lang 
    136     else: 
    137         if localefile: 
    138             _appTranslate = gettext.translation(domain, localedir, languages=[lang], codeset=charset) 
    139             if _appTranslate: 
    140                 _appTranslate.add_fallback(_daboTranslate) 
    141             return bool(_appTranslate) 
    142         return False 
    143          
    144  
    145 defLang, defCharset = ("en", "utf-8") 
    146 #defLang, defCharset = locale.getdefaultlocale() 
    147  
    148 #if defLang is None: 
    149 #   defLang = "en" 
    150 #else: 
    151 #   defLang = defLang[:2] 
    152 #if defCharset is None: 
    153 #   defCharset = "UTF-8" 
    154  
    155 setLanguage(domain="dabo") 
    156  
    157 if __name__ == "__main__": 
    158     print "user default locale:", locale.getdefaultlocale() 
    159     print "framework locale:", defLang, defCharset 
    160  
    161     for lan in ("en", "es"): 
    162         setLanguage(lan) 
    163         print "%s:" % lan, _("Framework localization test") 
    164  
  • trunk/dabo/dObject.py

    r3276 r3290  
    99from dabo.lib.autosuper import autosuper 
    1010from dabo.dPref import dPref 
    11 from dabo.dLocalize import _ 
    1211 
    1312class Dummy(object): 
  • trunk/dabo/dPref.py

    r3226 r3290  
    44import datetime 
    55import dabo 
    6 from dabo.dLocalize import _ 
    76import dabo.lib.utils as utils 
    87 
  • trunk/dabo/dReportWriter.py

    r3193 r3290  
    11# -*- coding: utf-8 -*- 
    2 from dabo.dLocalize import _ 
    32from dabo.lib.reportWriter import ReportWriter 
    43from dabo.dObject import dObject 
  • trunk/dabo/dSecurityManager.py

    r3054 r3290  
    22import time 
    33from dabo.dObject import dObject 
    4 from dLocalize import _ 
    54 
    65 
  • trunk/dabo/dUserSettingProvider.py

    r3054 r3290  
    22import dabo 
    33from dabo.dObject import dObject 
    4 from dabo.dLocalize import _ 
    54 
    65 
  • trunk/dabo/db/dBackend.py

    r3216 r3290  
    44import datetime 
    55import dabo 
    6 from dabo.dLocalize import _ 
    76import dabo.dException as dException 
    87from dabo.dObject import dObject 
  • trunk/dabo/db/dConnectInfo.py

    r3199 r3290  
    44from dabo.lib.connParser import importConnections 
    55from dabo.dObject import dObject 
    6 from dabo.dLocalize import _ 
    76from dabo.lib.SimpleCrypt import SimpleCrypt 
    87 
  • trunk/dabo/db/dConnection.py

    r3106 r3290  
    11# -*- coding: utf-8 -*- 
    2 from dabo.dLocalize import _ 
    32from dabo.dObject import dObject 
    43from dConnectInfo import dConnectInfo 
  • trunk/dabo/db/dCursorMixin.py

    r3229 r3290  
    1818import dabo 
    1919import dabo.dConstants as kons 
    20 from dabo.dLocalize import _ 
    2120import dabo.dException as dException 
    2221from dabo.dObject import dObject 
  • trunk/dabo/db/dDataSet.py

    r3199 r3290  
    33import re 
    44import dabo 
    5 from dabo.dLocalize import _ 
    65import datetime 
    76 
  • trunk/dabo/db/dTable.py

    r3054 r3290  
    11# -*- coding: utf-8 -*- 
    2 from dabo.dLocalize import _ 
    32import dabo.dException as dException 
    43from dabo.dObject import dObject 
  • trunk/dabo/db/dbFirebird.py

    r3225 r3290  
    33import re 
    44import dabo 
    5 from dabo.dLocalize import _ 
    65from dBackend import dBackend 
    76from dCursorMixin import dCursorMixin 
  • trunk/dabo/db/dbMsSQL.py

    r3250 r3290  
    11# -*- coding: utf-8 -*- 
    22import datetime 
    3 from dabo.dLocalize import _ 
    43from dBackend import dBackend 
    54 
  • trunk/dabo/db/dbMySQL.py

    r3106 r3290  
    55except ImportError: 
    66    decimal = None 
    7 from dabo.dLocalize import _ 
    87from dBackend import dBackend 
    98import dabo.dException as dException 
  • trunk/dabo/db/dbOracle.py

    r3106 r3290  
    2525""" 
    2626import datetime 
    27 from dabo.dLocalize import _ 
    2827from dBackend import dBackend 
    2928 
  • trunk/dabo/db/dbPostgreSQL.py

    r3179 r3290  
    11# -*- coding: utf-8 -*- 
    22import datetime 
    3 from dabo.dLocalize import _ 
    43from dBackend import dBackend 
    54 
  • trunk/dabo/db/dbSQLite.py

    r3238 r3290  
    33import os 
    44import re 
    5 from dabo.dLocalize import _ 
    65from dBackend import dBackend 
    76from dNoEscQuoteStr import dNoEscQuoteStr as dNoEQ 
  • trunk/dabo/db/dbTemplate.py

    r3106 r3290  
    2525""" 
    2626import datetime 
    27 from dabo.dLocalize import _ 
    2827from dBackend import dBackend 
    2928 
  • trunk/dabo/lib/DesignerXmlConverter.py

    r3170 r3290  
    1111dabo.ui.loadUI("wx") 
    1212import dabo.dEvents as dEvents 
    13 from dabo.dLocalize import _ 
    1413from dabo.dObject import dObject 
    1514import dabo.ui.dialogs as dlgs 
  • trunk/dabo/lib/datanav/Form.py

    r3054 r3290  
    77import dabo.ui 
    88from dabo.lib.specParser import importRelationSpecs, importFieldSpecs 
    9 from dabo.dLocalize import _, n_ 
    109import dabo.lib.reportUtils as reportUtils 
    1110import PageFrame 
  • trunk/dabo/lib/datanav/Grid.py

    r3054 r3290  
    1111import dabo.dException as dException 
    1212dabo.ui.loadUI("wx") 
    13 from dabo.dLocalize import _, n_ 
    1413import dabo.dEvents as dEvents 
    1514 
  • trunk/dabo/lib/datanav/Page.py

    r3199 r3290  
    66import dabo.dException as dException 
    77import dabo.dEvents as dEvents 
    8 from dabo.dLocalize import _, n_ 
    98from dabo.lib.utils import padl 
    109from dabo.dObject import dObject 
  • trunk/dabo/lib/datanav/PageFrame.py

    r3054 r3290  
    44import dabo.dEvents as dEvents 
    55import Page as pag 
    6 from dabo.dLocalize import _, n_ 
    76 
    87dabo.ui.loadUI("wx") 
  • trunk/dabo/lib/datanav/__init__.py

    r3054 r3290  
    11# -*- coding: utf-8 -*- 
    22import warnings 
    3 from dabo.dLocalize import _ 
    43from Form import Form 
    54from Grid import Grid 
  • trunk/dabo/lib/datanav2/Form.py

    r3151 r3290  
    55import dabo.dEvents as dEvents 
    66import dabo.ui 
    7 from dabo.dLocalize import _, n_ 
    87import dabo.lib.reportUtils as reportUtils 
    98import PageFrame 
  • trunk/dabo/lib/datanav2/Grid.py

    r3076 r3290  
    44import dabo.dException as dException 
    55dabo.ui.loadUI("wx") 
    6 from dabo.dLocalize import _, n_ 
    76import dabo.dEvents as dEvents 
    87 
  • trunk/dabo/lib/datanav2/Page.py

    r3054 r3290  
    55import dabo.dException as dException 
    66import dabo.dEvents as dEvents 
    7 from dabo.dLocalize import _, n_ 
    87from dabo.lib.utils import padl 
    98from dabo.dObject import dObject 
     
    1211import Grid 
    1312 
    14 IGNORE_STRING, CHOICE_TRUE, CHOICE_FALSE = (n_("-ignore-"), 
    15         n_("Is True"), 
    16         n_("Is False") ) 
    17  
    18 ASC, DESC = (n_("asc"), n_("desc")) 
     13IGNORE_STRING, CHOICE_TRUE, CHOICE_FALSE = ("-ignore-", "Is True", "Is False") 
     14 
     15ASC, DESC = ("asc", "desc") 
    1916 
    2017# Controls for the select page: 
     
    374371        if typ in ("char", "memo"): 
    375372            if typ == "char": 
    376                 chcList = [n_("Equals"),  
    377                         n_("Begins With"), 
    378                         n_("Contains")] 
     373                chcList = ["Equals", "Begins With", "Contains"] 
    379374            elif typ == "memo": 
    380                 chcList = [n_("Begins With"), 
    381                         n_("Contains")] 
     375                chcList = ["Begins With", "Contains"] 
    382376            if wordSearch: 
    383                 chcList.append(n_("Matches Words")
     377                chcList.append("Matches Words"
    384378            chc = tuple(chcList) 
    385379        elif typ in ("date", "datetime"): 
    386             chc = (n_("Equals")
    387                     n_("On or Before")
    388                     n_("On or After")
    389                     n_("Before")
    390                     n_("After")
     380            chc = ("Equals"
     381                    "On or Before"
     382                    "On or After"
     383                    "Before"
     384                    "After"
    391385        elif typ in ("int", "float", "decimal"): 
    392             chc = (n_("Equals"),  
    393                     n_("Greater than")
    394                     n_("Greater than/Equal to")
    395                     n_("Less than")
    396                     n_("Less than/Equal to")
     386            chc = ("Equals",  
     387                    "Greater than"
     388                    "Greater than/Equal to"
     389                    "Less than"
     390                    "Less than/Equal to"
    397391        elif typ == "bool": 
    398392            chc = (CHOICE_TRUE, CHOICE_FALSE) 
  • trunk/dabo/lib/datanav2/PageFrame.py

    r3054 r3290  
    33import dabo.dEvents as dEvents 
    44import Page as pag 
    5 from dabo.dLocalize import _, n_ 
    65 
    76 
  • trunk/dabo/lib/eventMixin.py

    r3240 r3290  
    44import traceback 
    55import dabo 
    6 from dabo.dLocalize import _ 
    76 
    87 
  • trunk/dabo/lib/logger.py

    r3196 r3290  
    22import sys, os, time 
    33from dabo.dObject import dObject 
    4 from dabo.dLocalize import _ 
    54 
    65class Log(dObject): 
  • trunk/dabo/lib/propertyHelperMixin.py

    r3128 r3290  
    11# -*- coding: utf-8 -*- 
    22import string 
    3 from dabo.dLocalize import _ 
    43 
    54 
  • trunk/dabo/lib/reportWriter.py

    r3285 r3290  
    5454from dabo.lib.xmltodict import xmltodict 
    5555from dabo.lib.xmltodict import dicttoxml 
    56 from dabo.dLocalize import _ 
    5756from dabo.lib.caselessDict import CaselessDict 
    5857from reportlab.lib.utils import ImageReader 
  • trunk/dabo/lib/xmltodict.py

    r3253 r3290  
    1313import dabo 
    1414import dabo.lib.DesignerUtils as desUtil 
    15 from dabo.dLocalize import _ 
    1615from dabo.lib.utils import resolvePath 
    1716app = dabo.dAppRef 
  • trunk/dabo/ui/__init__.py

    r3199 r3290  
    1515import os, traceback 
    1616import dabo 
    17 from dabo.dLocalize import _ 
    1817 
    1918 
  • trunk/dabo/ui/dControlMixinBase.py

    r3276 r3290  
    44import dabo 
    55import dabo.ui 
    6 from dabo.dLocalize import _ 
    76import dabo.dEvents as dEvents 
    87 
  • trunk/dabo/ui/dDataControlMixinBase.py

    r3281 r3290  
    77import dabo.dException as dException 
    88from dabo.dObject import dObject 
    9 from dabo.dLocalize import _ 
    109 
    1110 
  • trunk/dabo/ui/dPemMixinBase.py

    r3054