kopia lustrzana https://github.com/wagtail/wagtail
Merge 0c98880d60
into 7c6187f06c
commit
e5b92cd742
1
setup.py
1
setup.py
|
@ -31,7 +31,6 @@ install_requires = [
|
|||
"beautifulsoup4>=4.8,<4.13",
|
||||
"Willow[heif]>=1.8.0,<2",
|
||||
"requests>=2.11.1,<3.0",
|
||||
"l18n>=2018.5",
|
||||
"openpyxl>=3.0.10,<4.0",
|
||||
"anyascii>=0.1.5",
|
||||
"telepath>=0.3.1,<1",
|
||||
|
|
|
@ -0,0 +1,249 @@
|
|||
"""
|
||||
Utility to download and generate timezone translations for the Wagtail admin
|
||||
from the Unicode Consortium CLDR. This only needs to be run if
|
||||
WAGTAILADMIN_PROVIDED_LANGUAGES changes or if timezones in pytz change.
|
||||
|
||||
This script will output ``.po`` files with mostly automated translations.
|
||||
Language experts should review these and make necessary adjustments.
|
||||
"""
|
||||
|
||||
# Import from standard library.
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
import urllib
|
||||
|
||||
# Setup django so we can import things from Wagtail.
|
||||
import django # noqa
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "wagtail.tests.settings")
|
||||
django.setup()
|
||||
|
||||
|
||||
import polib # noqa
|
||||
import pytz # noqa
|
||||
from wagtail.admin.localization import WAGTAILADMIN_PROVIDED_LANGUAGES # noqa
|
||||
|
||||
|
||||
URL = "https://raw.githubusercontent.com/unicode-org/cldr-json/39.0.0/cldr-json"
|
||||
|
||||
|
||||
# Since CLDR territories do not exactly match CLDR timezone territories, use
|
||||
# these similar replacements which *do* exist in CLDR territory database.
|
||||
TERRITORY_ALIASES = {
|
||||
# "Timezone territory": "CLDR territory"
|
||||
"America": "Americas",
|
||||
}
|
||||
|
||||
|
||||
# Timezones which may be formatted differently between pytz and CLDR. Note that
|
||||
# the pytz zone is always retained as the value; the CLDR zone or metazone is
|
||||
# used purely for translation purposes. Aliases and deprecations can be looked
|
||||
# up here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
ZONE_ALIASES = {
|
||||
# "pytz zone": "CLDR zone"
|
||||
"Africa/Asmara": "Africa/Nairobi",
|
||||
"America/Argentina/Buenos_Aires": "America/Buenos_Aires",
|
||||
"America/Argentina/Catamarca": "America/Catamarca",
|
||||
"America/Argentina/Cordoba": "America/Cordoba",
|
||||
"America/Argentina/Jujuy": "America/Jujuy",
|
||||
"America/Argentina/Mendoza": "America/Mendoza",
|
||||
"America/Atikokan": "America/Coral_Harbour",
|
||||
"America/Indiana/Indianapolis": "America/Indianapolis",
|
||||
"America/Kentucky/Louisville": "America/Louisville",
|
||||
"America/Knox_IN": "America/Indiana/Knox",
|
||||
"Asia/Ho_Chi_Minh": "Asia/Saigon",
|
||||
"Asia/Kathmandu": "Asia/Katmandu",
|
||||
"Asia/Kolkata": "Asia/Calcutta",
|
||||
"Asia/Yangon": "Asia/Rangoon",
|
||||
"Atlantic/Faroe": "Atlantic/Faeroe",
|
||||
"Pacific/Chuuk": "Pacific/Truk",
|
||||
"Pacific/Pohnpei": "Pacific/Ponape",
|
||||
"UTC": "Etc/UTC",
|
||||
}
|
||||
METAZONE_ALIASES = {
|
||||
# "pytz zone": "CLDR metazone"
|
||||
"Canada/Atlantic": "Atlantic",
|
||||
"Canada/Central": "America_Central",
|
||||
"Canada/Eastern": "America_Eastern",
|
||||
"Canada/Mountain": "America_Mountain",
|
||||
"Canada/Newfoundland": "Newfoundland",
|
||||
"Canada/Pacific": "America_Pacific",
|
||||
"GMT": "GMT",
|
||||
"US/Alaska": "Alaska",
|
||||
"US/Central": "America_Central",
|
||||
"US/Eastern": "America_Eastern",
|
||||
"US/Hawaii": "Hawaii_Aleutian",
|
||||
"US/Mountain": "America_Mountain",
|
||||
"US/Pacific": "America_Pacific",
|
||||
}
|
||||
|
||||
|
||||
# Simce timezones are formatted as ``Territory/City``, but the CLDR database
|
||||
# only provides translations for the City, first create a map of territories
|
||||
# based on the English version. Then flip {key:value} so they are keyed by
|
||||
# territory name instead of ID (so we can easily look up the IDs later).
|
||||
TERRITORY_MAP = {}
|
||||
uri = f"{URL}/cldr-localenames-full/main/en/territories.json"
|
||||
with urllib.request.urlopen(uri) as r:
|
||||
data = json.loads(r.read().decode("utf-8"))
|
||||
data = data["main"]["en"]["localeDisplayNames"]["territories"]
|
||||
for key in data:
|
||||
value = data[key]
|
||||
TERRITORY_MAP[value] = key
|
||||
|
||||
|
||||
def _get_city(z: dict) -> str:
|
||||
"""
|
||||
Gets the exemplar city, long/generic, or long/standard name within a given
|
||||
CLDR zone dictionary.
|
||||
"""
|
||||
city = z.get("exemplarCity", "")
|
||||
if not city and z.get("long"):
|
||||
city = z["long"].get("generic", z["long"].get("standard", ""))
|
||||
return city
|
||||
|
||||
|
||||
def _get_territory(t: dict, name: str) -> str:
|
||||
"""
|
||||
Gets the translated territory name from a given CDLR territory dictionary.
|
||||
"""
|
||||
ter_id = TERRITORY_MAP.get(TERRITORY_ALIASES.get(name, name))
|
||||
return t.get(ter_id, "")
|
||||
|
||||
|
||||
def _download_json(uri: str) -> dict:
|
||||
"""
|
||||
Downloads the requested URI and returns as a json-parsed dictionary.
|
||||
"""
|
||||
with urllib.request.urlopen(uri) as r:
|
||||
data = json.loads(r.read().decode("utf-8"))
|
||||
return data
|
||||
|
||||
|
||||
# For each language supported by Wagtail admin, download territory and timezone
|
||||
# translations from the Unicode consortium and convert it into a Python message
|
||||
# file (``.po`` and ``.mo``).
|
||||
time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M%z")
|
||||
for item in WAGTAILADMIN_PROVIDED_LANGUAGES:
|
||||
lang = item[0]
|
||||
|
||||
# Download territories in the language.
|
||||
cldr_territories = {}
|
||||
print(f"Downloading territories for {lang}...") # noqa: T201
|
||||
uri = f"{URL}/cldr-localenames-full/main/{lang}/territories.json"
|
||||
try:
|
||||
data = _download_json(uri)
|
||||
except urllib.error.HTTPError:
|
||||
# Try alternate form of language...
|
||||
lang = lang.split("-")[0]
|
||||
uri = f"{URL}/cldr-localenames-full/main/{lang}/territories.json"
|
||||
data = _download_json(uri)
|
||||
|
||||
cldr_territories = data["main"][lang]["localeDisplayNames"]["territories"]
|
||||
|
||||
# Download timezones in the language.
|
||||
cldr_timezones = {}
|
||||
cldr_metazones = {}
|
||||
print(f"Downloading timezones for {lang}...") # noqa: T201
|
||||
uri = f"{URL}/cldr-dates-full/main/{lang}/timeZoneNames.json"
|
||||
try:
|
||||
data = _download_json(uri)
|
||||
except urllib.error.HTTPError:
|
||||
# Try alternate form of language...
|
||||
lang = lang.split("-")[0]
|
||||
uri = f"{URL}/cldr-dates-full/main/{lang}/timeZoneNames.json"
|
||||
data = _download_json(uri)
|
||||
|
||||
cldr_timezones = data["main"][lang]["dates"]["timeZoneNames"]["zone"]
|
||||
cldr_metazones = data["main"][lang]["dates"]["timeZoneNames"]["metazone"]
|
||||
|
||||
# Make the message file.
|
||||
po = polib.POFile()
|
||||
po.metadata = {
|
||||
"Project-Id-Version": "Wagtail",
|
||||
"PO-Revision-Date": time,
|
||||
"Last-Translator": "translate.py",
|
||||
"Language-Team": (
|
||||
"The Unicode Consortium CLDR " "<https://github.com/unicode-org/cldr-json>"
|
||||
),
|
||||
"MIME-Version": "1.0",
|
||||
"Content-Type": "text/plain; charset=utf-8",
|
||||
"Content-Transfer-Encoding": "8bit",
|
||||
}
|
||||
|
||||
# Add entry for each common timezone.
|
||||
for pytz_name in pytz.common_timezones:
|
||||
# print(pytz_name)
|
||||
timezone = ZONE_ALIASES.get(pytz_name, pytz_name)
|
||||
metazone = METAZONE_ALIASES.get(pytz_name, None)
|
||||
zones = timezone.split("/")
|
||||
|
||||
trans_territory = ""
|
||||
trans_city = ""
|
||||
|
||||
# If this is a metazone, process it separately.
|
||||
if metazone:
|
||||
# Translate first part of zone as territory.
|
||||
ter = _get_territory(cldr_territories, zones[0])
|
||||
if ter:
|
||||
trans_territory += f"{ter}/"
|
||||
|
||||
# Translate the metazone as a city.
|
||||
trans_city = _get_city(cldr_metazones[metazone])
|
||||
|
||||
else:
|
||||
# Traverse variable number of zones to get to the city, e.g.
|
||||
# America/Indiana/East
|
||||
exists = True
|
||||
z = cldr_timezones
|
||||
for subzone in zones:
|
||||
try:
|
||||
z = z[subzone]
|
||||
except KeyError:
|
||||
print(f"WARNING: '{timezone}' not found in '{lang}'.") # noqa: T201
|
||||
exists = False
|
||||
|
||||
# If this zone does not have an exemplarCity/long, try to
|
||||
# translate it from the regions.
|
||||
if not exists or not (z.get("exemplarCity") or z.get("long")):
|
||||
ter = _get_territory(cldr_territories, subzone)
|
||||
if ter:
|
||||
trans_territory += f"{ter}/"
|
||||
|
||||
if not exists:
|
||||
break
|
||||
|
||||
# If this zone exists, get the exemplarCity or the long generic or
|
||||
# long standard name.
|
||||
if exists:
|
||||
trans_city = _get_city(z)
|
||||
|
||||
# Show UTC as "UTC/<name>" rather than our usual format of "Etc/<name>".
|
||||
if pytz_name == "UTC":
|
||||
trans_territory = "UTC/"
|
||||
|
||||
# Re-combine using translated territory and city.
|
||||
trans_entry = pytz_name
|
||||
if trans_territory and trans_city:
|
||||
trans_entry = f"{trans_territory}{trans_city}"
|
||||
elif trans_territory:
|
||||
trans_entry = f"{trans_territory}{zones[-1]}"
|
||||
elif trans_city:
|
||||
trans_entry = f"{zones[0]}/{trans_city}"
|
||||
|
||||
entry = polib.POEntry(msgid=pytz_name, msgstr=trans_entry)
|
||||
po.append(entry)
|
||||
|
||||
# Save the message file.
|
||||
path = os.path.join(
|
||||
os.path.dirname(__name__),
|
||||
"wagtail",
|
||||
"admin",
|
||||
"locale",
|
||||
lang,
|
||||
"LC_MESSAGES",
|
||||
)
|
||||
os.makedirs(path, exist_ok=True)
|
||||
po.save(os.path.join(path, "timezones.po"))
|
||||
po.save_as_mofile(os.path.join(path, "timezones.mo"))
|
|
@ -1,7 +1,6 @@
|
|||
import types
|
||||
from functools import wraps
|
||||
|
||||
import l18n
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.shortcuts import redirect
|
||||
|
@ -141,7 +140,6 @@ def require_admin_access(view_func):
|
|||
preferred_language = (
|
||||
user.wagtail_userprofile.get_preferred_language()
|
||||
)
|
||||
l18n.set_language(preferred_language)
|
||||
time_zone = user.wagtail_userprofile.get_current_time_zone()
|
||||
else:
|
||||
time_zone = settings.TIME_ZONE
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import warnings
|
||||
from operator import itemgetter
|
||||
|
||||
import l18n
|
||||
from django import forms
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db.models.fields import BLANK_CHOICE_DASH
|
||||
|
@ -11,6 +10,7 @@ from django.utils.translation import gettext_lazy as _
|
|||
from wagtail.admin.localization import (
|
||||
get_available_admin_languages,
|
||||
get_available_admin_time_zones,
|
||||
gettext_domain,
|
||||
)
|
||||
from wagtail.admin.widgets import SwitchInput
|
||||
from wagtail.permissions import page_permission_policy
|
||||
|
@ -60,8 +60,7 @@ def _get_language_choices():
|
|||
|
||||
def _get_time_zone_choices():
|
||||
time_zones = [
|
||||
(tz, str(l18n.tz_fullnames.get(tz, tz)))
|
||||
for tz in get_available_admin_time_zones()
|
||||
(tz, gettext_domain("timezones", tz)) for tz in get_available_admin_time_zones()
|
||||
]
|
||||
time_zones.sort(key=itemgetter(1))
|
||||
return BLANK_CHOICE_DASH + time_zones
|
||||
|
|
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
|
@ -1,6 +1,10 @@
|
|||
import gettext
|
||||
import os
|
||||
|
||||
import pytz
|
||||
from django.conf import settings
|
||||
from django.utils.dates import MONTHS, WEEKDAYS, WEEKDAYS_ABBR
|
||||
from django.utils.translation import get_language
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
# Wagtail languages with >=90% coverage
|
||||
|
@ -107,3 +111,22 @@ def get_available_admin_time_zones():
|
|||
return []
|
||||
|
||||
return getattr(settings, "WAGTAIL_USER_TIME_ZONES", pytz.common_timezones)
|
||||
|
||||
|
||||
def gettext_domain(domain: str, message: str) -> str:
|
||||
"""
|
||||
Similar to Django's ``gettext``, return the translation for a specific
|
||||
domain (i.e. a specific ``.po`` file).
|
||||
"""
|
||||
if settings.USE_I18N:
|
||||
# Get current language, and fallback to non-specific version of language.
|
||||
langs = [get_language()] + [get_language().split("-")[0]]
|
||||
lc_path = os.path.join(os.path.dirname(__file__), "locale")
|
||||
_gt = gettext.translation(
|
||||
domain,
|
||||
localedir=lc_path,
|
||||
languages=langs,
|
||||
fallback=True,
|
||||
)
|
||||
return _gt.gettext(message)
|
||||
return message
|
||||
|
|
Ładowanie…
Reference in New Issue