Replaces gettext loc with custom

Adds tool to extract strings
Allows config file to specify locale
This commit is contained in:
Steve Dower 2016-02-16 11:25:00 -08:00
Родитель 1146a74c7e
Коммит d014e9b38b
8 изменённых файлов: 145 добавлений и 88 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -9,7 +9,6 @@ env/
.ptvs/
# Build results
bin/
obj/
dist/
MANIFEST

Просмотреть файл

@ -1,62 +0,0 @@
syntax: glob
# Python cache
__pycache__/
*.pyc
# Virtual environment
env/
# PTVS analysis
.ptvs/
# Build results
bin/
obj/
dist/
MANIFEST
# Result of running python setup.py install/pip install -e
RECORD.txt
build/
*.egg-info/
# Test results
TestResults/
# Credentials
credentials_real.json
testsettings_local.json
servicebus_settings_real.py
storage_settings_real.py
legacy_mgmt_settings_real.py
mgmt_settings_real.py
app_creds_real.py
# User-specific files
*.suo
*.user
*.sln.docstates
.vs/
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Mac desktop service store files
.DS_Store
.idea
src/build
*.iml
/doc/_build
/.vs/config/applicationhost.config
# Azure deployment credentials
*.pubxml

30
bin/extract-loc.py Normal file
Просмотреть файл

@ -0,0 +1,30 @@
#! /usr/bin/env python3
import os
import re
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent / "src" / "azure" / "cli"
OUTPUT = ROOT / "locale" / "en-US" / "messages.txt"
print('Extracting from:', ROOT)
if not ROOT.is_dir():
print("Failed to locate 'azure/cli'")
sys.exit(1)
if not OUTPUT.parent.is_dir():
os.makedirs(str(OUTPUT.parent))
with open(str(OUTPUT), 'w', encoding='utf-8-sig') as f_out:
for path in ROOT.rglob('*.py'):
with open(str(path), 'r', encoding='utf-8') as f:
content = f.read()
for m in re.finditer('[^\w_]_\(("(.+)"|\'(.+)\')\)', content):
print('# From', path, ':', m.span()[0], file=f_out)
print('KEY:', m.group(2) or m.group(3), file=f_out)
print(m.group(2) or m.group(3), file=f_out)
print(file=f_out)

Просмотреть файл

@ -3,6 +3,7 @@ import json
import os
import sys
from ._locale import get_file as locale_get_file
from ._logging import logging
# Named arguments are prefixed with one of these strings
@ -63,15 +64,12 @@ class ArgumentParser(object):
def __init__(self, prog):
self.prog = prog
self.noun_map = {
'$doc': 'azure-cli',
'$doc': 'azure-cli.txt',
}
self.help_args = { '--help', '-h' }
self.complete_args = { '--complete' }
self.global_args = { '--verbose', '--debug' }
self.doc_source = './'
self.doc_suffix = '.txt'
def add_command(self, handler, name=None, description=None, args=None):
'''Registers a command that may be parsed by this parser.
@ -98,7 +96,7 @@ class ArgumentParser(object):
for n in nouns:
full_name += n
m = m.setdefault(n.lower(), {
'$doc': full_name
'$doc': full_name + ".txt"
})
full_name += '.'
m['$description'] = description or handler.__doc__
@ -234,7 +232,7 @@ class ArgumentParser(object):
print(' {0:<{1}} - {2}'.format(a, maxlen, d), file=out)
print(file=out, flush=True)
doc_file = os.path.join(self.doc_source, noun_map['$doc'] + self.doc_suffix)
doc_file = locale_get_file(noun_map['$doc'])
try:
with open(doc_file, 'r') as f:
print(f.read(), file=out, flush=True)

30
src/azure/cli/_locale.py Normal file
Просмотреть файл

@ -0,0 +1,30 @@
import os.path
from codecs import open
def install(locale_dir):
mapping = []
with open(os.path.join(locale_dir, "messages.txt"), 'r', encoding='utf-8-sig') as f:
for i in f:
if not i or i.startswith('#') or not i.strip():
continue
if i.startswith('KEY: '):
mapping.append((i[5:].strip(), None))
else:
mapping[-1] = (mapping[-1][0], i.strip())
translations = dict(mapping)
def _(key):
return translations.get(key) or '<NO_TRANSLATION:{}>'.format(key)
_.locale_dir = locale_dir
__builtins__['_'] = _
def get_file(name):
try:
src = _.locale_dir
except (NameError, AttributeError):
raise RuntimeError("localizations not installed")
return os.path.join(src, name)

Просмотреть файл

@ -1,6 +1,8 @@
import logging as _logging
import sys
__all__ = ['logging', 'configure_logging']
_CODE_LEVEL = _logging.INFO + 1
class Logger(_logging.Logger):
@ -30,28 +32,26 @@ def _arg_name(arg):
return a.lower()
def configure_logging(argv, config):
# TODO: Configure logging handler to log messages to .py file
# Thinking here:
# INFO messages as Python code
# DEBUG messages (if -v) as comments
# WARNING/ERROR messages as clearly marked comments
# Currently we just use the default format
level = _logging.WARNING
# Load logging info from config
if config.get('verbose'):
level = _logging.INFO
if config.get('debug'):
level = _logging.DEBUG
logfile = config.get('log')
logfile = None
# Load logging info from arguments
# Also remove any arguments consumed so that the parser does not
# have to explicitly ignore them.
i = 0
while i < len(argv):
arg = _arg_name(argv[i])
if arg in ('v', 'verbose'):
level = _logging.INFO
level = min(_logging.INFO, level)
argv.pop(i)
elif arg in ('debug',):
level = _logging.DEBUG
level = min(_logging.DEBUG, level)
argv.pop(i)
elif arg in ('log',):
argv.pop(i)
@ -61,20 +61,22 @@ def configure_logging(argv, config):
pass
else:
i += 1
logging.setLevel(_logging.INFO)
# Configure the console output handler
stderr_handler = _logging.StreamHandler(sys.stderr)
stderr_handler.formatter = _logging.Formatter('%(levelname)s: %(message)s')
stderr_handler.level = level
logging.level = stderr_handler.level = level
logging.handlers.append(stderr_handler)
if logfile and logfile.lower().endswith('.py'):
# Configure a handler that logs code to a Python script
py_handler = _logging.StreamHandler(open(logfile, 'w', encoding='utf-8'))
py_handler.formatter = PyFileFormatter()
py_handler.level = level if level == _logging.DEBUG else _logging.INFO
logging.handlers.append(py_handler)
elif logfile:
# Configure the handler that logs code to a text file
log_handler = _logging.StreamHandler(open(logfile, 'w', encoding='utf-8'))
log_handler.formatter = _logging.Formatter('[%(levelname)s:%(asctime)s] %(message)s')
log_handler.level = level if level == _logging.DEBUG else _logging.INFO
logging.handlers.append(log_handler)
logging.handlers.append(log_handler)

Просмотреть файл

@ -0,0 +1,60 @@
# From D:\Repos\azure-cli\src\azure\cli\_argparse.py : 1208
KEY: Argument {0} is required
Argument {0} is required
# From D:\Repos\azure-cli\src\azure\cli\_argparse.py : 6848
KEY: argument '{0}' does not take a value
argument '{0}' does not take a value
# From D:\Repos\azure-cli\src\azure\cli\commands\login.py : 1147
KEY: user password or service principal secret, will prompt if not given.
user password or service principal secret, will prompt if not given.
# From D:\Repos\azure-cli\src\azure\cli\commands\login.py : 1253
KEY: If given, log in as a service principal rather than a user.
If given, log in as a service principal rather than a user.
# From D:\Repos\azure-cli\src\azure\cli\commands\login.py : 1367
KEY: A PEM encoded certificate private key file.
A PEM encoded certificate private key file.
# From D:\Repos\azure-cli\src\azure\cli\commands\login.py : 1454
KEY: A hex encoded thumbprint of the certificate.
A hex encoded thumbprint of the certificate.
# From D:\Repos\azure-cli\src\azure\cli\commands\login.py : 1535
KEY: Tenant domain or ID to log into.
Tenant domain or ID to log into.
# From D:\Repos\azure-cli\src\azure\cli\commands\login.py : 1597
KEY: do not prompt for confirmation of PII storage.
do not prompt for confirmation of PII storage.
# From D:\Repos\azure-cli\src\azure\cli\commands\login.py : 1927
KEY: Unknown environment {0}
Unknown environment {0}
# From D:\Repos\azure-cli\src\azure\cli\commands\login.py : 2091
KEY: Tenant:
Tenant:
# From D:\Repos\azure-cli\src\azure\cli\commands\login.py : 2381
KEY: Password:
Password:
# From D:\Repos\azure-cli\src\azure\cli\commands\login.py : 2883
KEY: No subscriptions found for this account
No subscriptions found for this account
# From D:\Repos\azure-cli\src\azure\cli\commands\login.py : 2991
KEY: Setting subscription %s as default
Setting subscription %s as default
# From D:\Repos\azure-cli\src\azure\cli\commands\storage.py : 268
KEY: the resource group name
the resource group name
# From D:\Repos\azure-cli\src\azure\cli\commands\storage.py : 332
KEY: the subscription id
the subscription id

Просмотреть файл

@ -1,9 +1,7 @@
import gettext
import os
gettext.install("az", os.path.join(os.path.abspath(__file__), '..', 'locale'))
from ._argparse import ArgumentParser
from ._locale import install as locale_install
from ._logging import configure_logging, logging
from ._session import Session
@ -13,6 +11,11 @@ CONFIG = Session()
# SESSION provides read-write session variables
SESSION = Session()
# Load the user's preferred locale from their configuration
LOCALE = CONFIG.get('locale', 'en-US')
locale_install(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'locale', LOCALE))
def main(args):
CONFIG.load(os.path.expanduser('~/az.json'))
SESSION.load(os.path.expanduser('~/az.sess'), max_age=3600)
@ -22,9 +25,6 @@ def main(args):
parser = ArgumentParser("az")
import azure.cli.commands as commands
parser.doc_source = os.path.dirname(commands.__file__)
# TODO: detect language
parser.doc_suffix = '.en_US.txt'
# Find the first noun on the command line and only load commands from that
# module to improve startup time.