Module:Autolink

From NeuroWiki
Revision as of 22:49, 31 October 2024 by Selfice (talk | contribs) (创建页面,内容为“local p = {} local static = require( 'Module:Static' ) if not static.Autolink then static.Autolink = {} end local commonPrefix = 'Module:Autolink/' local commonFallback = 'Other' local function getDataSource( src ) if type( static.Autolink.globalDataSource ) ~= 'table' then static.Autolink.globalDataSource = {} end if not src or src == '' then return nil end if src:find( '#' ) then local splits = mw.text.split( src, '#' ) if not static.Autolink…”)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Autolink,即自动链接,用于给模板的参数中的英文转换为对应的中文并显示出来,正如Module:Reverselink能将中文参数转换为英文并提供给模板以显示图片。

本模块主要用于:

数据模块

本模块采用以下子页面中的数据:

这些页面中的每条数据可以按下面2种形式中的任意一种来组织:

  • ['注册名'] = '输出内容',
    • 只包含输出内容,不包含任何flag,所有flag均采用其默认值。
  • ['注册名'] = { '输出内容', flag1, flag2, ... },
    • 指定用于控制特殊行为的flag。各flag的顺序及其含义见grabFlags函数中的定义,目前定义如下:
      • flag1,引用名hide,可选注册名hide:布尔值,用于控制对应项目是否不在标准译名列表中出现。false为出现,true为不出现,默认值false。
      • flag2,引用名cg,可选注册名cg:Lua表,用于手动指定转换规则,适用于未纳入简繁转换表的情况,数据传入Module:STConversion处理。默认为nil。包括下列键名:
        • 1zh-tw:-{台灣正體}-的名称。1的优先级较高。
        • 2zh-hk:-{香港繁體}-的名称。2的优先级较高。
        • zh-cn:-{大陆简体}-的名称,设置后会替代原始名称。

依赖项


en:Module:Autolink/doc



local p = {}

local static = require( 'Module:Static' )
if not static.Autolink then
	static.Autolink = {}
end

local commonPrefix = 'Module:Autolink/'
local commonFallback = 'Other'

local function getDataSource( src )
	if type( static.Autolink.globalDataSource ) ~= 'table' then
		static.Autolink.globalDataSource = {}
	end
	if not src or src == '' then
		return nil
	end
	if src:find( '#' ) then
		local splits = mw.text.split( src, '#' )
		if not static.Autolink.globalDataSource[ splits[ 1 ] ] then
			static.Autolink.globalDataSource[ splits[ 1 ] ] = mw.loadData( commonPrefix .. splits[ 1 ] )
		end
		return static.Autolink.globalDataSource[ splits[ 1 ] ][ splits[ 2 ] ]
	else
		if not static.Autolink.globalDataSource[ src ] then
			static.Autolink.globalDataSource[ src ] = mw.loadData( commonPrefix .. src )
		end
		return static.Autolink.globalDataSource[ src ]
	end
end

local function grabFlags( tbl, key )
	local entry = tbl[ key ]
	if not entry then
		return nil
	end
	local result = {
		hide = false,
		cg = nil,
	}
	if type( entry ) == 'table' then
		if tbl[ key ][ 2 ] then
			result.hide = tbl[ key ][ 2 ]
		end
		if tbl[ key ].hide then
			result.hide = tbl[ key ].hide
		end
		if tbl[ key ][ 3 ] then
			result.cg = tbl[ key ][ 3 ]
		end
		if tbl[ key ].cg then
			result.cg = tbl[ key ].cg
		end
	end
	return result
end

local function grabName( tbl, key )
	if not tbl[ key ] then
		return nil
	end
	local str = nil
	if type( tbl[ key ] ) == 'string' then
		str = tbl[ key ]
	elseif type( tbl[ key ] ) == 'table' then
		str = tbl[ key ].raw or tbl[ key ][ 1 ]
	else
		return nil
	end
	local index = str:find( '|' )
	local result = { conv = nil }
	if index then
		result.link = str:sub( 1, index - 1 )
		result.name = str:sub( index + 1 )
	else
		result.link = str
		result.name = str
	end
	local flags = grabFlags( tbl, key )
	if flags and flags.cg then
		result.conv = require( 'Module:STConversion' ).call{
			flags.cg[ 'zh-cn' ] or result.name,
			flags.cg[ 1 ] or flags.cg[ 'zh-tw' ],
			flags.cg[ 2 ] or flags.cg[ 'zh-hk' ],
		}
	end
	return result
end

local function grabNameTwice( tbl, key )
	local result = grabName( tbl, key )
	if not result and key:sub( -1 ) == 's' then
		result = grabName( tbl, key:sub( 0, -2 ) )
	end
	return result
end

local function outputFormatter( tbl, mode, suffix )
	if not tbl then
		return nil
	end
	if mode == 'linkonly' then
		return tbl.link
	end
	if mode == 'nolink' then
		return ( tbl.conv or tbl.name ) .. ( suffix or '' )
	end
	if mode == 'name' then
		return tbl.name .. ( suffix or '' )
	end
	if not tbl.conv and tbl.link == tbl.name then
		return tbl.name .. ( suffix or '' )
	else
		return tbl.link .. '|' .. ( tbl.conv or tbl.name ) .. ( suffix or '' )
	end
end

-- used by templates, called via #invoke
function p.link( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = require( 'Module:ProcessArgs' ).merge( true )
	end
	return p.invlink( args[ 1 ] , args[ 2 ] , args[ 3 ], args.notypefallback )
end

function p.invlink( str, mode, spritetype, notypefallback )
	local arg = str:gsub ( '-', ' ' ):lower()

	local be = nil
	local lce = nil
	-- check for version suffix
	if arg:find( ' pe$' ) or arg:find( ' be$' ) then
		be = true
		arg = arg:sub( 0, -4 )
	end
	if arg:find( ' lce$' ) then
		lce = true
		arg = arg:sub( 0, -5 )
	end

	-- runtime registry generator
	if not static.Autolink.coreRegistry then
		static.Autolink.coreRegistry = {
			data = {},
			list = {},
			raw = {
				-- For maintainers: This "raw" table of registry indicates what sequence should follow while searching inside certain types and fallback to other types.
				-- New type MUST be registered here, otherwise the data stored in associated data modules will not be loaded and read.
				-- The meaning and format should as follows:
				-- Data Source Type                 Internal Searching Sequence
				{ 'BlockSprite'                , { 'Block',                                'Exclusive#BlockSprite',  'Earth#BlockSprite' } },
				{ 'ItemSprite'                 , { 'Item',                                 'Exclusive#ItemSprite' ,  'Earth#ItemSprite'  } },
				{ 'EntitySprite'               , { 'Entity',                               'Exclusive#EntitySprite'                      } },
				{ 'BiomeSprite'                , { 'Biome'                                                                               } },
				{ 'EffectSprite'               , { 'Effect'                                                                              } },
				{ nil                          , { 'Enchantment'                                                                         } },
				{ 'EnvSprite'                  , { 'Environment'                                                                         } },
				{ 'DungeonsItemSprite'         , { 'Dungeons#DungeonsItemSprite'                                                         } },
				{ 'DungeonsEntitySprite'       , { 'Dungeons#DungeonsEntitySprite'                                                       } },
				{ 'DungeonsEnchantmentSprite'  , { 'Dungeons#DungeonsEnchantmentSprite'                                                  } },
				{ 'DungeonsLevelSprite'        , { 'Dungeons#DungeonsLevelSprite'                                                        } },
				{ 'DungeonsEmoteSprite'        , { 'Dungeons#DungeonsEmoteSprite'                                                        } },
				{ 'DungeonsFlairSprite'        , { 'Dungeons#DungeonsFlairSprite'                                                        } },
				{ 'DungeonsMiscellaneousSprite', { 'Dungeons#DungeonsMiscellaneousSprite'                                                } },
				{ 'LegendsEntitySprite'        , { 'Legends#LegendsEntitySprite'                                                         } },
				{ 'LegendsStructureSprite'     , { 'Legends#LegendsStructureSprite'                                                      } },
				{ 'LegendsMiscellaneousSprite' , { 'Legends#LegendsMiscellaneousSprite'                                                  } },
				{ 'LegendsBiomeSprite'         , { 'Legends#LegendsBiomeSprite'                                                          } },
				{ 'EarthEntitySprite'          , { 'Earth#EarthEntitySprite'                                                             } },
				{ 'StoryModeCharacterSprite'   , { 'Story Mode#StoryModeCharacterSprite'                                                 } },
				{ 'InvSprite'                  , { 'Other',                                'Earth#InvSprite'                             } },
				-- Data Source Type: Must be the same as the "data" argument in sprite and sprite-link templates.
				--	If Autolink cannot find a name in the type passed by argument "spritetype" (or third argument a template passed), Autolink will continue searching in other types from up to bottom (in table order), unless argument "notypefallback" is set.
				--	If set to nil, this entry will be ignored.
				-- Internal Searching Sequence: Must be a subpage name for a Autolink data module.
				--	If Autolink cannot find a name in the first data source, Autolink will continue searching in other data soruces from left to right (in table order).
				--	If contains "#", it means data will be selected from a section in this data module, only level-1 sections are supported.
				--	e.g. "Exclusive#BlockSprite" means it will select the section "BlockSprite" from data module "Exclusive".
				--	If not contains "#", it means data will be selected from the whole data module.
				--	e.g. "BlockSprite" means it will select the all contents from data module "Block".
			}
		}
		for _, v in pairs( static.Autolink.coreRegistry.raw ) do
			if v[ 1 ] then
				static.Autolink.coreRegistry.data[ v[ 1 ] ] = v[ 2 ]
				table.insert( static.Autolink.coreRegistry.list, v[ 1 ] )
			end
		end
	end

	local result = nil
	-- get name from the specified data source set
	if spritetype then
		for _, v in pairs( static.Autolink.coreRegistry.data[ spritetype ] or {} ) do
			result = grabNameTwice( getDataSource( v ), arg )
			if result then
				break
			end
		end
	end

	-- fallback to other data source sets
	if not notypefallback and not result then
		for _, current_key in pairs( static.Autolink.coreRegistry.list ) do
			if current_key ~= spritetype then
				for _, current_value in pairs( static.Autolink.coreRegistry.data[ current_key ] or {} ) do
					result = grabNameTwice( getDataSource( current_value ), arg )
					if result then
						break
					end
				end
				if result then
					break
				end
			end
		end
	end

	-- fallback to defined common fallback data source
	if not notypefallback and not result then
		result = grabNameTwice( getDataSource( commonFallback ), arg )
	end

	-- fallback to the string itself
	if not result then
		result = { name = str, link = str }
	end

	-- formatting
	if be then
		return outputFormatter( result, mode, '(基岩版)' )
	end
	if lce then
		return outputFormatter( result, mode, '(原主机版)' )
	end
	return outputFormatter( result, mode )
end

-- list out all entries with the type
function p.list( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = require( 'Module:ProcessArgs' ).merge( true )
	end

	local moduleSprite = require( 'Module:Sprite' ).sprite
	local moduleSpriteFile = require( 'Module:SpriteFile' ).sprite

	local dataRegistry = {
		block                 = { 'Block',                                'BlockSprite'                 },
		item                  = { 'Item',                                 'ItemSprite'                  },
		entity                = { 'Entity',                               'EntitySprite'                },
		biome                 = { 'Biome',                                'BiomeSprite'                 },
		effect                = { 'Effect',                               'EffectSprite'                },
		enchantment           = { 'Enchantment',                          ''                            },
		environment           = { 'Environment',                          'EnvSprite'                   },
		dungeonsitem          = { 'Dungeons#DungeonsItemSprite',          'DungeonsItemSprite'          },
		dungeonsentity        = { 'Dungeons#DungeonsEntitySprite',        'DungeonsEntitySprite'        },
		dungeonsenchantment   = { 'Dungeons#DungeonsEnchantmentSprite',   'DungeonsEnchantmentSprite'   },
		dungeonslevel         = { 'Dungeons#DungeonsLevelSprite',         'DungeonsLevelSprite'         },
		dungeonsemote         = { 'Dungeons#DungeonsEmoteSprite',         'DungeonsEmoteSprite'         },
		dungeonsflair         = { 'Dungeons#DungeonsFlairSprite',         'DungeonsFlairSprite'         },
		dungeonsmiscellaneous = { 'Dungeons#DungeonsMiscellaneousSprite', 'DungeonsMiscellaneousSprite' },
		legendsentity         = { 'Legends#LegendsEntitySprite',          'LegendsEntitySprite'         },
		legendsstructure      = { 'Legends#LegendsStructureSprite',       'LegendsStructureSprite'      },
		legendsmiscellaneous  = { 'Legends#LegendsMiscellaneousSprite',   'LegendsMiscellaneousSprite'  },
		legendsbiome          = { 'Legends#LegendsBiomeSprite',           'LegendsBiomeSprite'          },
		earthentity           = { 'Earth#EarthEntitySprite',              'EarthEntitySprite'           },
		storymodecharacter    = { 'Story Mode#StoryModeCharacterSprite',  'StoryModeCharacterSprite'    },
	}
	local migratedRegistry = {
		[ 'BiomeSprite' ] = true,
		[ 'EffectSprite' ] = true,
		[ 'DungeonsLevelSprite' ] = true,
		[ 'LegendsStructureSprite' ] = true,
		[ 'LegendsBiomeSprite' ] = true,
		[ 'LegendsEntitySprite' ] = true,
		[ 'LegendsMiscellaneousSprite' ] = true,
		[ 'StoryModeCharacterSprite' ] = true,
	}

	local type = args[ 1 ]:lower()
	if dataRegistry[ type ] == nil then
		return ''
	end
	local list = getDataSource( dataRegistry[ type ][ 1 ] )
	local sprite = dataRegistry[ type ][ 2 ]
	if not list or not sprite then
		return ''
	end

	local t = {}
	for k, _ in pairs( list ) do
		if not grabFlags( list, k ).hide then
			table.insert( t, k )
		end
	end
	table.sort( t )

	local header = mw.html.create( 'tr' )
	local spriteids = nil
	if sprite ~= '' then
		if not migratedRegistry[ sprite ] then
			spriteids = mw.loadData( 'Module:' .. sprite ).ids
		end
		header:tag( 'th' ):wikitext( '图标' )
	end
	header:tag( 'th' ):wikitext( '英文名称' )
	header:tag( 'th' ):wikitext( '中文名称' )

	local result = ''
	local count = 0
	local limit = 50
	local itemlist = nil
	for _, v in ipairs( t ) do
		if count == 0 then
			if itemlist ~= nil then
				result = result .. tostring( itemlist )
			end
			itemlist = mw.html.create( 'table' )
				:addClass( 'data-table' )
				:node( header )
		end

		local row = mw.html.create( 'tr' )
		if sprite ~= '' then
			if not migratedRegistry[ sprite ] then
				if spriteids[ v ] or spriteids[ mw.ustring.lower( v ):gsub( '[%s%+]', '-' ) ] then
					row:tag( 'td' ):wikitext( moduleSprite{ v, data = sprite } )
				elseif spriteids[ v .. 's' ] or spriteids[ mw.ustring.lower( v .. 's' ):gsub( '[%s%+]', '-' ) ] then
					row:tag( 'td' ):wikitext( moduleSprite{ v .. 's', data = sprite } )
				else
					row:tag( 'td' )
				end
			else
				row:tag( 'td' ):wikitext( moduleSpriteFile{ v, name = sprite } )
			end
		end

		local words = {}
		v:gsub( '[^%s]+', function( w ) table.insert( words, w ) end )
		for k, w in ipairs( words ) do
			if w == 'tnt' then
				words[ k ] = 'TNT'
			elseif w ~= 'of' and w ~= 'or' and w ~= 'o\'' then
				words[ k ] = w:gsub( '(%l)(.+)', function( a, b ) return a:upper() .. b end )
			end
		end
		row:tag( 'td' ):wikitext( table.concat( words, ' ' ) )

		row:tag( 'td' ):wikitext( outputFormatter( grabName( list, v ), 'nolink' ) )

		itemlist:node( row )

		count = count + 1
		if count == limit then
			count = 0
		end
	end

	result = result .. tostring( itemlist )
	return require( 'Module:TSLoader' ).call( 'Template:Data table/styles.css' ) .. result
end

return p