Недавно появилась задача — перевести карту студенческого городка на английский. Или хотя бы транслитерировать её, избавившись от кириллицы. Карта состоит из двух групп слоёв, в одной из них содержатся слои с маркерами, задаными яваскриптовым кодом — перевести их не составит труда, а вот растровый слой, подложку, поверх которой отображаются маркеры, перевести чуть сложнее — об этом сегодняшняя история.
Для того, чтоб иметь контроль над внешним видом подложки, не зависеть от размещающих тайлы (квадратные растровые фрагменты карт) сторонних сервисов, и не платить им денег в конце концов, тайлы генерируются из геоданных OpenStreetMap самостоятельно. OpenStreetMap для любого объекта может содержать множество имён — это и то, что хранится с ключом name
— имя вообще, и int_name
— международное имя, и куча имён с ключами вида name:ru
, name:en
, name:что_попало
. Если делать тайлы с помощью TileMill, а свой стиль создавать на основе OSM Bright, то доступно только одно имя — name
, однако в настройках сопоставления для imposm можно выбрать нужный язык — по умолчанию эта строка в файле imposm-mapping.py закомментирована:
set_default_name_type(LocalizedName(['name:en', 'int_name', 'name']))
Запускаем импорт, английские имена попадают в базу… Однако английских имён мало, сильно меньше, чем объектов с именами, записанными кириллицей.
Выхода из этой ситуации два — правильный и быстрый.
Правильный заключается в аккуратном переводе имён в OSM — слишком долго, да и неохота руками ковыряться.
Быстрый способ — не трогать OSM, а имена транслитерировать локально, в своём экземпляре базы данных. Так и поступим: создадим функцию транслитерации (прообраз подсмотрел на sql.ru) и выполним кучу UPDATE, вызывающих эту функцию. Мне, как перловому программисту, больше был симпатичен вариант с написанием перловой функции внутри PostgreSQL, но сразу такой вариант у меня не заработал, а разбираться было лень.
Итак, скармливаем постгресу такой код:
CREATE OR REPLACE FUNCTION ru_translit(p_string character varying)
RETURNS character varying AS
$BODY$
-- Transliteration of Cyrillic letters
select
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
translate(
$1,
'АБВГДЕЗИЙКЛМНОПРСТУФЫЭабвгдезийклмнопрстуфыэ',
'ABVGDEZIYKLMNOPRSTUFYEabvgdeziyklmnoprstufye'
),
'ё', 'yo'),
'ж', 'zh'),
'х', 'kh'),
'ц', 'ts'),
'ч', 'ch'),
'ш', 'sh'),
'щ', 'shch'),
'ъ', ''),
'ь', ''),
'э', 'e'),
'ю', 'yu'),
'я', 'ya'),
'Ё', 'Yo'),
'Ж', 'Zh'),
'Х', 'Kh'),
'Ц', 'Ts'),
'Ч', 'Ch'),
'Ш', 'Sh'),
'Щ', 'Shch'),
'Ъ', ''),
'Ь', ''),
'Э', 'E'),
'Ю', 'Yu'),
'Я', 'Ya');
$BODY$
LANGUAGE sql IMMUTABLE
COST 100;
UPDATE osm_admin SET name=ru_translit(name);
UPDATE osm_aeroways SET name=ru_translit(name);
UPDATE osm_amenities SET name=ru_translit(name);
UPDATE osm_barrierpoints SET name=ru_translit(name);
UPDATE osm_barrierways SET name=ru_translit(name);
UPDATE osm_buildings SET name=ru_translit(name);
UPDATE osm_landusages SET name=ru_translit(name);
UPDATE osm_landusages_gen0 SET name=ru_translit(name);
UPDATE osm_landusages_gen1 SET name=ru_translit(name);
UPDATE osm_mainroads SET name=ru_translit(name);
UPDATE osm_mainroads_gen0 SET name=ru_translit(name);
UPDATE osm_mainroads_gen1 SET name=ru_translit(name);
UPDATE osm_minorroads SET name=ru_translit(name);
UPDATE osm_motorways SET name=ru_translit(name);
UPDATE osm_motorways_gen0 SET name=ru_translit(name);
UPDATE osm_motorways_gen1 SET name=ru_translit(name);
UPDATE osm_places SET name=ru_translit(name);
UPDATE osm_railways SET name=ru_translit(name);
UPDATE osm_railways_gen0 SET name=ru_translit(name);
UPDATE osm_railways_gen1 SET name=ru_translit(name);
UPDATE osm_transport_points SET name=ru_translit(name);
UPDATE osm_waterareas SET name=ru_translit(name);
UPDATE osm_waterareas_gen0 SET name=ru_translit(name);
UPDATE osm_waterareas_gen1 SET name=ru_translit(name);
UPDATE osm_waterways SET name=ru_translit(name);
Если мы добавляли номера домов на карту — транслитерируем и их заодно:
UPDATE osm_buildings SET "addr:housenumber"=ru_translit("addr:housenumber");
После чего можно запускать отрисовку своих тайлов — кириллицы там уже не будет.