This is a private module sandbox of Suzukaze-c, for their own experimentation. Items in this module may be added and removed at Suzukaze-c's discretion; do not rely on this module's stability.
--[==[
TODO:
*
** juubako & yutou
*** automatic → need to examine original entry title?
** "|yomi=x,x3"
** kan'youon, goon, etc? ] (いつの間に?)
** disable "cat:read as x" categories for irregular readings!!
** sortkeys
**
* "cat:read with on'yomi" "secondary school kanji" "one kanji" etc?
* read data from "cat:字 read as じ", or read data from "字#Readings"?
** have "cat:" and "{{ja-kanjitab}}" read from "#Readings"
* ]
]==]
local export = {}
local gsub = mw.ustring.gsub
local match = mw.ustring.match
local split = mw.text.split
-- XXX: share this data with ]?
local yomi_class_aliases = {
= "on",
= "kun",
= "irregular",
= "irregular",
}
local yomi_class_data = {
= {
text = "on’yomi",
entry = "音読み",
category = "Japanese terms read with on'yomi",
},
= {
text = "kun’yomi",
entry = "訓読み",
category = "Japanese terms read with kun'yomi",
},
= {
text = "yutōyomi",
entry = "湯桶読み",
category = "Japanese terms read with yutōyomi",
},
= {
text = "jūbakoyomi",
entry = "重箱読み",
category = "Japanese terms read with jūbakoyomi",
},
= {
text = "kan’yōon",
entry = "慣用音",
category = "Japanese terms read with kan'yōon",
},
= {
text = "nanori",
entry = "名乗り読み",
category = "Japanese terms read with nanori",
},
= {
text = "<i>irregular</i>",
category = "Japanese terms with irregular kanji readings",
},
}
local kanji_grade_links = {
']',
']',
']',
']',
']',
']',
']', -- 7
']', -- 8
']' -- 9
}
local category_models = {
= "Japanese terms spelled with %s read as %s",
= "Japanese terms with rendaku",
= "Japanese terms with omitted okurigana",
}
local function tag_text(text)
return require('Module:script utilities').tag_text(text, require('Module:languages').getByCode('ja'))
end
local function clean_reading(reading)
reading = gsub(reading, '%(+%)', '')
reading = gsub(reading, '>.+', '')
return reading
end
local function analyze_reading(categories, char, reading)
if not reading then
return
end
-- error checking
if match(reading, '>') then
if match(reading, '%(') and not match(reading, '.+%(.+%)>.+%(.+%)') then
error('Please fix your parentheses.')
-- BUT maybe "かた>がた(り)" is nicer than "かた(り)>がた(り)"
end
elseif match(reading, '<') then
error('Please show sound change in the ">" direction.')
end
if match(reading, '') and not match(reading, '.+%(.+%)') then
error('Please close your parentheses.')
end
-- 本番
if match(reading, '%(') then
table.insert(categories, category_models)
reading = gsub(reading, '%(+%)', '')
end
if match(reading, '>') then
local reading_forms = split(reading, '>')
-- if reading_forms == gsub(mw.ustring.toNFD(reading_forms), '', '') then
--
local kanaA = mw.ustring.sub(reading_forms, 1, 1) -- pre-rendaku kana
local kanaB = mw.ustring.sub(reading_forms, 1, 1) -- post-rendaku kana
kanaB = mw.ustring.char(mw.ustring.codepoint(kanaB) - 1) -- strip dakuon
kanaC = mw.ustring.char(mw.ustring.codepoint(kanaB) - 1) -- strip dakuon again, for パ行
if (kanaA == kanaB) or (kanaA == kanaC) then
table.insert(categories, category_models)
end
reading = gsub(reading, '>.+', '')
end
table.insert(categories, category_models:format(char, reading))
end
local function build_tab_row_b_cell(char, reading)
local tab_row_b_cell = mw.html.create('td')
local kanji_grade = require('Module:ja').kanji_grade(char)
if reading then
-- reading = gsub(reading, '>', '<sub>></sub>')
-- reading = gsub(reading, '%(+%)', '<sup>%1</sup>')
reading = gsub(reading, '>', '→')
tab_row_b_cell
:wikitext(tag_text(reading))
:tag('br')
:done()
end
tab_row_b_cell
:wikitext('<small>' .. kanji_grade_links .. '</small>')
:done()
return tab_row_b_cell
end
local function build_tab_row_c(tab_row_c, yomi, chars)
for i, yomi_class in ipairs(yomi) do
yomi = yomi_class_aliases or yomi_class -- "o"→"on"
yomi = yomi_class_data].text -- "on"→"on’yomi"
end
if #yomi == 1 then
local tab_row_c_cell = mw.html.create('td')
:attr('colspan', #chars)
:wikitext(yomi)
:done()
tab_row_c
:node(tab_row_c_cell)
:done()
else
local tab_row_c_cells = {}
for i, yomi_class in ipairs(yomi) do
if (yomi == yomi) then
tab_row_c_cells
:attr('colspan', tab_row_c_cells:getAttr('colspan') + 1)
:done()
else
local tab_row_c_cell = mw.html.create('td')
:wikitext(yomi)
:attr('colspan', 1)
:done()
table.insert(tab_row_c_cells, tab_row_c_cell)
end
end
for i, tab_row_c_cell in ipairs(tab_row_c_cells) do
tab_row_c
:node(tab_row_c_cell)
:done()
end
end
return tab_row_c
end
local function detect_yomi_classes(chars, readings)
local yomi = {}
for i, char in ipairs(chars) do
if readings then
local category_name = category_models:format(char, clean_reading(readings))
local category_content = mw.title.new(category_name, 'Category'):getContent()
if not category_content then
error('Please verify that ] is formatted correctly, or fill out the "yomi" parameter.')
end
category_content = gsub(category_content, '^{{', '')
category_content = gsub(category_content, '}}$', '')
category_content = split(category_content, '|')
table.remove(category_content, 1) -- "ja-readingcat"
table.remove(category_content, 1) --
table.remove(category_content, 1) --
-- XXX: 🤔
local detected_yomi_types = ''
for i, yomi_type in ipairs(category_content) do
if match(yomi_type, 'on$') then
detected_yomi_types = detected_yomi_types .. '0'
else
detected_yomi_types = detected_yomi_types .. '1'
end
end
if match(detected_yomi_types, '01') or match(detected_yomi_types, '10') then
error('Could not determine if ] was an on reading or a kun reading; please fill out the "yomi" parameter.')
elseif match(detected_yomi_types, '0') then
yomi = 'o'
else
yomi = category_content -- 🤔
end
else
-- yomi = ''
error('reading was not provided for ]?')
end
end
return yomi
end
function export.main(data)
local tab_row_b = mw.html.create('tr')
local tab_row_c = mw.html.create('tr')
local categories = {}
if data.yomi then
data.yomi = split(data.yomi, ',')
elseif data.readings then
data.yomi = detect_yomi_classes(data.chars, data.readings)
end
if table.maxn(data.yomi) ~= 1 then
if table.maxn(data.yomi) ~= table.maxn(data.readings) then
error(table.maxn(data.readings) .. ' readings and ' .. table.maxn(data.yomi) .. ' yomi designations?')
end
end
for i, char in ipairs(data.chars) do
tab_row_b
:node(build_tab_row_b_cell(char, data.readings))
:done()
analyze_reading(categories, char, data.readings)
end
if data.yomi then
tab_row_c = build_tab_row_c(tab_row_c, data.yomi, data.chars)
end
data.hani_tab
:node(tab_row_b)
:node(tab_row_c)
:done()
return data.hani_tab, categories
end
return export