local export = {}
local m_links = require("Module:links")
local m_lang = require("Module:languages")
local ain = m_lang.getByCode("ain")
local dial_data = mw.loadData("Module:ain-dial-map/data")
local radius = 0.001
local colors = {
"d2502e", "6941c7", "9fdd42", "e7ff79", "b66063",
"30bcff", "c6ceff", "02f291", "2e1200", "a4ff46",
"ffcccf", "63001e", "c124de", "00ae2d", "ff4ce4",
"6fff8b", "b900b1", "bfff6b", "0035b6", "fffe8d",
"61008c", "adff9e", "d463ff", "3c8a00", "db0098",
"00c97f", "a20090", "01a145", "ff5ec8", "59ffc6",
"e50025", "01c0cc", "a60003", "02b9db", "d37200",
"0151c6", "949900", "00156f", "ffa938", "290062",
"b69700", "6d87ff", "c88100", "014592", "ff823e",
"000f36", "bdffc4", "1e003b", "ffce7a", "320029",
"d5ffea", "6a0050", "009267", "ff4c61", "019282",
"fd98ff", "094300", "ad96ff", "965a00", "8eb0ff",
"761f00", "9bd8ff", "490d00", "fbffe9", "1d000f",
"feecff", "00141e", "ffddad", "001b14", "ff93ce",
"004f23", "9d0050", "005e5e", "ffa291", "003e33",
"ff9cac", "00536c", "ffc594", "0079b1", "5a3600",
"ff6b6b", "4ecdc4", "f7fff7", "ffe66d", "1a535c",
"457b9d", "a8dadc", "e63946", "f1faee", "2a9d8f",
"e9c46a", "f4a261", "e76f51", "264653", "2b2d42",
"8d99ae", "edf2f4", "ef233c", "d90429", "ffc8dd",
"ffafcc", "bde0fe", "a2d2ff", "cdb4db", "ffcbf2",
"f3c4fb", "ecbcfd", "e5dbff", "e2eAFC", "cfbaf0"
}
local symbols = {
"circle", "star", "square", "triangle", "marker", "rocket", "shop", "school", "park", "music",
"cemetery", "airport", "rail", "bus", "bicycle", "bar", "cafe", "town-hall", "roadblock"
}
local katakana_map = {
['トゥ'] = 'tu', ['ドゥ'] = 'du',
['チャ'] = 'ca', ['チュ'] = 'cu', ['チェ'] = 'ce', ['チョ'] = 'co',
['ジャ'] = 'ja', ['ジュ'] = 'ju', ['ジェ'] = 'je', ['ジョ'] = 'jo',
['イェ'] = 'ye',
['ウィ'] = 'wi', ['ウェ'] = 'we', ['ウォ'] = 'wo',
['ㇷ゚'] = 'p',
['ッ'] = 't', ['ㇰ'] = 'k', ['ㇱ'] = 's', ['ㇺ'] = 'm',
['ㇵ'] = 'h', ['ㇶ'] = 'h', ['ㇷ'] = 'h', ['ㇸ'] = 'h', ['ㇹ'] = 'h',
['ㇻ'] = 'r', ['ㇼ'] = 'r', ['ㇽ'] = 'r', ['ㇾ'] = 'r', ['ㇿ'] = 'r',
['ア'] = 'a', ['イ'] = 'i', ['ウ'] = 'u', ['エ'] = 'e', ['オ'] = 'o',
['カ'] = 'ka', ['キ'] = 'ki', ['ク'] = 'ku', ['ケ'] = 'ke', ['コ'] = 'ko',
['ガ'] = 'ga', ['ギ'] = 'gi', ['グ'] = 'gu', ['ゲ'] = 'ge', ['ゴ'] = 'go',
['サ'] = 'sa', ['シ'] = 'si', ['ス'] = 'su', ['セ'] = 'se', ['ソ'] = 'so',
['ザ'] = 'za', ['ジ'] = 'ji', ['ズ'] = 'zu', ['ゼ'] = 'ze', ['ゾ'] = 'zo',
['タ'] = 'ta', ['チ'] = 'ci', ['テ'] = 'te', ['ト'] = 'to',
['ダ'] = 'da', ['ヂ'] = 'di', ['デ'] = 'de', ['ド'] = 'do',
['ナ'] = 'na', ['ニ'] = 'ni', ['ヌ'] = 'nu', ['ネ'] = 'ne', ['ノ'] = 'no',
['ハ'] = 'ha', ['ヒ'] = 'hi', ['フ'] = 'hu', ['ヘ'] = 'he', ['ホ'] = 'ho',
['バ'] = 'ba', ['ビ'] = 'bi', ['ブ'] = 'bu', ['ベ'] = 'be', ['ボ'] = 'bo',
['パ'] = 'pa', ['ピ'] = 'pi', ['プ'] = 'pu', ['ペ'] = 'pe', ['ポ'] = 'po',
['マ'] = 'ma', ['ミ'] = 'mi', ['ム'] = 'mu', ['メ'] = 'me', ['モ'] = 'mo',
['ヤ'] = 'ya', ['ユ'] = 'yu', ['ヨ'] = 'yo',
['ラ'] = 'ra', ['リ'] = 'ri', ['ル'] = 'ru', ['レ'] = 're', ['ロ'] = 'ro',
['ワ'] = 'wa', ['ン'] = 'n'
}
local katakana_keys = {}
for k in pairs(katakana_map) do
table.insert(katakana_keys, k)
end
table.sort(katakana_keys, function(a, b)
return mw.ustring.len(a) > mw.ustring.len(b)
end)
local function katakanaToAlphabet(text)
local first_pass_result = ""
local i = 1
while i <= mw.ustring.len(text) do
local found_match = false
for _, key in ipairs(katakana_keys) do
local key_len = mw.ustring.len(key)
if mw.ustring.sub(text, i, i + key_len - 1) == key then
first_pass_result = first_pass_result .. katakana_map[key]
i = i + key_len
found_match = true
break
end
end
if not found_match then
first_pass_result = first_pass_result .. mw.ustring.sub(text, i, i)
i = i + 1
end
end
local second_pass_result = ""
local last_vowel = ""
for char in mw.ustring.gmatch(first_pass_result, ".") do
if char == 'ー' then
if last_vowel ~= "" then
second_pass_result = second_pass_result .. last_vowel
end
else
second_pass_result = second_pass_result .. char
local current_char_as_vowel = char:match("[aiueo]")
if current_char_as_vowel then
last_vowel = current_char_as_vowel
end
end
end
local final_result = second_pass_result
:gsub("au", "aw")
:gsub("iu", "iw")
:gsub("eu", "ew")
:gsub("ou", "ow")
:gsub("ai", "ay")
:gsub("ui", "uy")
:gsub("ei", "ey")
:gsub("oi", "oy")
return final_result
end
local function delink(text)
text = text:gsub("%[%[[^|%[%]]+|([^|%[%]]+)%]%]","%1")
:gsub("%[%[([^|%[%]]+)%]%]","%1")
return text
end
function export.make_list(data)
return "<ul><li>" .. table.concat(data,"</li><li>") .. "</li></ul>"
end
function export.map_header(text)
return tostring(
mw.html.create("h2")
:wikitext(text)
:done()
)
end
function export.get_coords(lat,long,i,n)
if n > 1 then
return {long+radius*math.cos(2*math.pi*i/n),lat+radius*math.sin(2*math.pi*i/n)}
else
return {long,lat}
end
end
function export.make_point(lat,long,color,text,i,n,symbol)
return {
type = "Feature",
properties = {
title = text,
["marker-color"] = color,
["marker-size"] = "small",
["marker-symbol"] = symbol,
},
geometry = {
type = "Point",
coordinates = export.get_coords(lat,long,i,n)
}
}
end
function export.make_polygon(text,color,points)
local coords = {}
for _,pt in ipairs(points) do
table.insert(coords,{pt.long,pt.lat})
end
table.insert(coords,{points[1].long,points[1].lat})
return {
type = "Feature",
properties = {
title = text,
["stroke-width"] = 0,
["fill"] = color,
["fill-opacity"] = 0,
},
geometry = {
type = "Polygon",
coordinates = {coords},
}
}
end
function export.legend(colour, show, cat, hide)
return tostring(
mw.html.create("div")
:addClass("ain-dial-map__legend-row")
:addClass((colour == grey and "ain-dial-map__legend-row-other" or nil))
:tag("div")
:addClass("vsSwitcher")
:attr("data-toggle-category", cat)
:attr("data-vs-showtext", "lects ▼")
:attr("data-vs-hidetext", "lects ▲")
:tag("span")
:addClass("ain-dial-map__legend-row-dot")
:css("background-color", "#" .. colour)
:wikitext("")
:done()
:tag("span")
:addClass("vsToggleElement")
:wikitext("")
:done()
:wikitext(show)
:tag("div")
:addClass("vsHide")
:wikitext(hide)
:allDone()
)
end
function export.make_legends(legend)
local r = #legend%5
local q = math.floor(#legend/5)
local d1 = q+(r>0 and 1 or 0)
local d2 = d1+q+(r>1 and 1 or 0)
local d3 = d2+q+(r>2 and 1 or 0)
local d4 = d3+q+(r>3 and 1 or 0)
local l1 = table.concat(legend,"",1,d1)
local l2 = table.concat(legend,"",d1+1,d2)
local l3 = table.concat(legend,"",d2+1,d3)
local l4 = table.concat(legend,"",d3+1,d4)
local l5 = table.concat(legend,"",d4+1,#legend)
local cell = {width="20%",["vertical-align"]="top"}
return tostring(
mw.html.create("table"):css("width","100%"):tag("tr")
:tag("td"):css(cell):wikitext(l1):done()
:tag("td"):css(cell):wikitext(l2):done()
:tag("td"):css(cell):wikitext(l3):done()
:tag("td"):css(cell):wikitext(l4):done()
:tag("td"):css(cell):wikitext(l5):done()
:allDone()
)
end
function export.make_map(frame,geojson,legend)
return tostring(
mw.html.create("div")
:addClass("thumb")
:addClass("ain-dial-map__container")
:wikitext(frame:extensionTag("mapframe",mw.text.jsonEncode(geojson),{
class = "ain-dial-map__map",
mapstyle = "osm-intl",
width = 1200,
height = 650,
latitude = 46.5,
longitude = 148,
zoom = 6
}))
:done()
:tag("div")
:wikitext(legend)
:done()
:done()
)
end
function export.show(frame)
local geojson = {}
local legend = {}
local dial = mw.loadData("Module:dialect synonyms/ain").varieties
local syn = mw.loadData("Module:dialect synonyms/ain/"..frame.args[1])
local lects = {}
local layer = {dial}
while layer[1] do
local children = {}
for _,node in ipairs(layer) do
if node[1] then
for _,child in ipairs(node) do
table.insert(children,child)
end
elseif node.long and syn.syns[node.name] and syn.syns[node.name][1] ~= "" then
table.insert(lects,node)
end
end
layer = children
end
local locs = {}
local n = {}
for _,lect in ipairs(lects) do
local syn_lect = syn.syns[lect.name]
n[lect.name] = 0
local i = 0
for _,original_form in ipairs(syn_lect) do
local key_form = original_form:gsub(":.*", "")
i = i + 1
n[lect.name] = n[lect.name] + 1
locs[key_form] = locs[key_form] or {}
table.insert(locs[key_form],{lect, i, original_form})
end
end
local forms = {}
for form,lects in pairs(locs) do
table.insert(forms,form)
end
table.sort(forms, function(a,b) return #locs[a] > #locs[b]
or (#locs[a] == #locs[b] and a > b) end)
for idx,form in ipairs(forms) do
local color = colors[idx]
local legend_lects = {}
local alphabet_form = katakanaToAlphabet(form)
local symbol_for_category = symbols[(idx - 1) % #symbols + 1]
local link = m_links.full_link({
lang = ain,
term = form,
})
local legend_display = link .. "(" .. alphabet_form .. ")" .. " (" .. #locs[form] .. ")"
for _,lect_i in ipairs(locs[form]) do
local lect, i, original_form = lect_i[1], lect_i[2], lect_i[3]
local display_word = delink(original_form)
local display = lect.text_display .. ": <br>" .. display_word
table.insert(geojson,export.make_point(lect.lat,lect.long,color,display,i,n[lect.name],symbol_for_category))
table.insert(legend_lects, lect.text_display)
end
table.insert(legend, export.legend(color, legend_display, form, export.make_list(legend_lects)))
end
local title = syn.title and syn.title ~= "" and syn.title or frame.args[1]
title = title:gsub("[0-9%-]", "")
local map_header = export.map_header(
"Map of Ainu varieties and languages for " .. m_links.full_link(
{
lang = ain,
term = title,
gloss = syn.meaning,
}
)
)
for _,fam in ipairs(dial_data.groups) do
table.insert(geojson,export.make_polygon(fam.name,fam.color,fam.points))
end
local legends = export.make_legends(legend)
local map = export.make_map(frame, geojson, legends)
return map_header .. map
end
return export