apostrophe/apostrophe/pylocales/locales.py

157 lines
5.4 KiB
Python
Raw Normal View History

2014-07-06 20:35:24 +00:00
# -*- coding:utf-8 -*-
#
2019-07-05 18:47:49 +00:00
# Copyright (C) 2019, Maximilian Köhl <linuxmaxi@googlemail.com>
# Copyright (C) 2019, Carlos Jenkins <carlos@jenkins.co.cr>
2014-07-06 20:35:24 +00:00
#
# 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
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Query the ISO 639/3166 database about a country or a language. The locales
2018-04-12 22:23:47 +00:00
database contains ISO 639 language definitions and ISO 3166 country definitions.
This package provides translation for country and language names if the
iso-code messages are installed on your system.
2014-07-06 20:35:24 +00:00
"""
import gettext
import logging
import os
import sqlite3
2018-04-12 22:23:47 +00:00
import sys
2014-07-06 20:35:24 +00:00
2018-04-12 22:23:47 +00:00
# public objects
2014-07-06 20:35:24 +00:00
__all__ = ['Country', 'Language', 'LanguageNotFound',
'CountryNotFound', 'code_to_name']
2018-04-12 22:23:47 +00:00
# translation
2014-07-06 20:35:24 +00:00
_translator_language = gettext.translation('iso_639', fallback=True).gettext
_translator_country = gettext.translation('iso_3166', fallback=True).gettext
# Decides where the database is located. If an application provides an
# os.path.get_module_path monkey patch to determine the path where the module
# is located it uses this. If not it searches in the directory of this source
# code file.
__path__ = None
if hasattr(os.path, 'get_module_path'):
__path__ = os.path.get_module_path(__file__)
if not os.path.isfile(os.path.join(__path__, 'locales.db')):
__path__ = None
if __path__ is None:
2018-04-12 22:23:47 +00:00
frozen = getattr(sys, 'frozen', None)
if frozen in ('dll', 'console_exe', 'windows_exe'):
__path__ = os.path.abspath(os.path.dirname(sys.executable))
elif frozen == 'macosx_app':
__path__ = os.path.abspath(os.environ['RESOURCEPATH'])
elif frozen is True:
# Handle executables produced by PyInstaller.
__path__ = sys._MEIPASS
else:
__path__ = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
2014-07-06 20:35:24 +00:00
2018-04-12 22:23:47 +00:00
# loading the database
2014-07-06 20:35:24 +00:00
_database = sqlite3.connect(os.path.join(__path__, 'locales.db'))
logger = logging.getLogger(__name__)
class LanguageNotFound(Exception):
"""
The specified language wasn't found in the database.
"""
class CountryNotFound(Exception):
"""
The specified country wasn't found in the database.
"""
class Country(object):
def __init__(self, rowid):
2018-04-12 22:23:47 +00:00
country = _database.execute('SELECT * FROM countries WHERE rowid == ?',
(rowid,)).fetchone()
2014-07-06 20:35:24 +00:00
self.name = country[0]
self.official_name = country[1]
self.alpha_2 = country[2]
self.alpha_3 = country[3]
self.numeric = country[4]
self.translation = _translator_country(self.name)
@classmethod
def get_country(cls, code, codec):
2018-04-12 22:23:47 +00:00
country = _database.execute(
'SELECT rowid FROM countries WHERE %s == ?' % (codec),
(code,)).fetchone()
2014-07-06 20:35:24 +00:00
if country:
return cls(country[0])
raise CountryNotFound('code: %s, codec: %s' % (code, codec))
@classmethod
def by_alpha_2(cls, code):
return Country.get_country(code, 'alpha_2')
@classmethod
def by_alpha_3(cls, code):
return Country.get_country(code, 'alpha_3')
@classmethod
def by_numeric(cls, code):
return Country.get_country(code, 'numeric')
class Language(object):
def __init__(self, rowid):
2018-04-12 22:23:47 +00:00
language = _database.execute('SELECT * FROM languages WHERE rowid == ?',
(rowid,)).fetchone()
2014-07-06 20:35:24 +00:00
self.name = language[0]
self.iso_639_2B = language[1]
self.iso_639_2T = language[2]
self.iso_639_1 = language[3]
self.translation = _translator_language(self.name)
@classmethod
def get_language(cls, code, codec):
2018-04-12 22:23:47 +00:00
language = _database.execute(
'SELECT rowid FROM languages WHERE %s == ?' % (codec),
(code,)).fetchone()
2014-07-06 20:35:24 +00:00
if language:
return cls(language[0])
raise LanguageNotFound('code: %s, codec: %s' % (code, codec))
@classmethod
def by_iso_639_2B(cls, code):
return Language.get_language(code, 'iso_639_2B')
@classmethod
def by_iso_639_2T(cls, code):
return Language.get_language(code, 'iso_639_2T')
@classmethod
def by_iso_639_1(cls, code):
return Language.get_language(code, 'iso_639_1')
def code_to_name(code, separator='_'):
2018-04-12 22:23:47 +00:00
"""
Get the human readable and translated name of a language based on it's code.
:param code: the code of the language (e.g. de_DE, en_US)
:param target: separator used to separate language from country
:rtype: human readable and translated language name
2014-07-06 20:35:24 +00:00
"""
logger.debug('requesting name for code "{}"'.format(code))
code = code.split(separator)
if len(code) > 1:
lang = Language.by_iso_639_1(code[0]).translation
country = Country.by_alpha_2(code[1]).translation
2018-04-12 22:23:47 +00:00
return '{} ({})'.format(lang, country)
2014-07-06 20:35:24 +00:00
else:
2018-04-12 22:23:47 +00:00
return Language.by_iso_639_1(code[0]).translation