Modul:TransText
Modul:TransText
| Vorlagenprogrammierung | Diskussionen | Lua | Unterseiten | |||
| Modul | Deutsch | English
|
Modul: | Dokumentation | ||
Diese Seite enthält Code in der Programmiersprache Lua. Einbindungszahl Cirrus
local TransText = { suite = "TransText",
serial = "2019-10-30",
item = 0,
globals = { ISO15924 = 71584769 } }
local Config = {
errBaseInvalid = { en = "Base code invalid",
de = "Ausgangscode ungültig" },
errBaseMissing = { en = "Base code missing",
de = "Ausgangscode fehlt" },
errBaseUnknown = { en = "Base code unknown:",
de = "Ausgangscode unbekannt:" },
errCompInvalid = { en = "Definition invalid",
de = "Definition ungültig" },
errCompMissing = { en = "Definition missing",
de = "Definition fehlt" },
errDefMissing = { en = "Definition module missing",
de = "Definitionsmodul fehlt" },
errTargetMissing = { en = "Target code missing",
de = "Zielcode fehlt" },
errTextCoding = { en = "Wrong encoding of base text",
de = "Schriftzeichen im Ausgangstext falsch" },
errTextMissing = { en = "Text missing",
de = "Ausgangstext fehlt" },
errTransCoding = { en = "Wrong encoding in result text",
de = "Schriftzeichen im Ergebnistext falsch" },
errMissing = { en = "Missing parameter",
de = "Parameter fehlt" },
errUnkown = { en = "Unkown parameter:",
de = "Parameter unbekannt:" }
}
local Failsafe = TransText
local GlobalMod = TransText
local Query = { slang = "und",
script = false,
template = { ["@"] = "lang",
["#"] = "1",
["*"] = "2" }
}
local Data
local foreignModule = function ( access, advanced, append, alt, alert )
-- Fetch global module
-- Precondition:
-- access -- string, with name of base module
-- advanced -- true, for require(); else mw.loadData()
-- append -- string, with subpage part, if any; or false
-- alt -- number, of wikidata item of root; or false
-- alert -- true, for throwing error on data problem
-- Postcondition:
-- Returns whatever, probably table
-- 2019-10-29
local storage = access
local finer = function ()
if append then
storage = string.format( "%s/%s",
storage,
append )
end
end
local fun, lucky, r, suited
if advanced then
fun = require
else
fun = mw.loadData
end
GlobalMod.globalModules = GlobalMod.globalModules or { }
suited = GlobalMod.globalModules[ access ]
if not suited then
finer()
lucky, r = pcall( fun, "Module:" .. storage )
end
if not lucky then
if not suited and
type( alt ) == "number" and
alt > 0 then
suited = string.format( "Q%d", alt )
suited = mw.wikibase.getSitelink( suited )
GlobalMod.globalModules[ access ] = suited or true
end
if type( suited ) == "string" then
storage = suited
finer()
lucky, r = pcall( fun, storage )
end
if not lucky and alert then
error( "Missing or invalid page: " .. storage, 0 )
end
end
return r
end -- foreignModule()
local function Feed( all )
local r = { }
local val
for k, v in pairs( all ) do
if type( k ) == "number" or k:match( "^%d" ) then
for ik, iv in pairs( all ) do
if type( iv ) == "table" then
val = Feed( iv )
else
val = iv
end
table.insert( r, val )
end -- for ik, iv
break -- for k, v
else
if type( v ) == "table" then
r[ k ] = Feed( v )
else
r[ k ] = v
end
end
end -- for k, v
return r
end -- Feed()
local function Fellow()
-- Attach ISO15924 library
-- Throws error, if library not existing
local r
if not TransText.ISO15924 then
local got = foreignModule( "ISO15924",
true,
false,
TransText.globals.ISO15924,
true )
if type( got ) == "table" and
type( got.ISO15924 ) == "function" then
TransText.ISO15924 = got.ISO15924()
end
if type( TransText.ISO15924 ) == "table" then
r = TransText.ISO15924
else
error( "Library ISO15924 unavailable" )
end
end
return r
end -- Fellow()
local function Fetch( at )
-- Attempt to load Data
-- Precondition:
-- at -- string, page name
-- Returns table, or not if invalid
-- Throws error, if not existing
local d = mw.loadData( at )
local r
if type( d ) == "table" and
type( d.data ) == "table" then
r = Feed( d.data )
else
r = { }
end
return r
end -- Fetch()
local function Frame()
-- Fetch current frame
-- Returns frame
if not Query.frame then
Query.frame = mw.getCurrentFrame()
end
return Query.frame
end -- Frame()
local function facility()
-- Fetch current site language
-- Returns language code
local r
if Data then
r = Data.stdLang
end
if not r then
r = mw.language.getContentLanguage():getCode()
if Data then
Data.stdLang = r
end
end
return r
end -- facility()
local function factory( apply )
-- Localization of messages
-- apply -- string, with message key
-- Returns message text; at least english
local entry = Config[ apply ]
local r
if entry then
r = entry[ facility() ]
if not r then
r = entry.en
end
else
r = string.format( "????.%s.????", apply )
end
return r
end -- factory()
local function failure( alert, about )
-- Format message with class="error"
-- alert -- string, with message key
-- about -- string, with explanation
-- Returns message with markup
local story = factory( alert )
local err = mw.html.create( "span" )
:addClass( "error" )
local env = Frame():getParent()
if env then
story = string.format( "[[%s]] – %s",
env:getTitle(), story )
end
if about then
story = string.format( "%s %s", story, about )
end
err:wikitext( story )
return tostring( err )
end -- failure()
local function fetch( assigned )
-- Load data page
-- Precondition:
-- assigned -- string or nil, for sub module
-- Returns table, if assigned, or not
-- Throws error, if not existing
local sub = string.format( "%s/data", Frame():getTitle() )
local r
if not Data then
Data = Fetch( sub )
end
if assigned then
sub = string.format( "%s/%s", sub, assigned )
r = Fetch( sub )
end
return r
end -- fetch()
local function fidelity( attempt, accept, after )
-- Check characters for compatibility with script
-- Precondition:
-- attempt -- string, source text
-- accept -- string, script specifier
-- after -- true: for result text
-- Returns false, if okay, else string with coding sequence
local bib = Fellow()
local r
if bib then
local e, cp = bib.isScript( accept, attempt )
if e then
r = false
else
local scream
if after then
scream = "errTransCoding"
else
scream = "errTextCoding"
end
r = failure( scream, bib.showScripts( cp ) )
end
end
return r
end -- fidelity()
local function finish( adjust, about )
-- Finalize template parameter text
-- Precondition:
-- adjust -- string, with source text
-- about -- string or nil, with script or lang code
-- Returns string, with source text
local r = adjust:gsub( "{{", "{{" )
:gsub( "|", "|" )
:gsub( "}}", "}}" )
if about and TransText.ISO15924.isRTL( about ) then
r = r .. "‎"
end
if not mw.isSubsting() then
r = r:gsub( "&(#?x?[lrm%x]+;)", "&%1" )
end
return r
end -- finish()
local function first( a1, a2 )
-- Compare a1 with a2
-- a1 -- string, with name
-- a2 -- string, with name
-- Returns true if a1 < a2
local f = function( a )
local d = { n = 0, s = "" }
local k = a
local s = type( k )
if s == "string" then
if k:match( "^%d+$" ) then
d.n = tonumber( k ) - 100
else
d.s = k
if k:match( "^%l+$" ) then
d.n = 0.1
elseif k:sub( 1, 3 ) == "ISO" then
local n, m = k:match( "^ISO(%d+)%-(%d+)$" )
if n then
d.n = tonumber( n )
+ tonumber( m ) * 0.0001
else
n = k:match( "^ISO(%d+)$" )
d.n = tonumber( n )
end
else
d.n = 1000000
end
end
elseif s == "number" then
d.n = k - 100
end
return d
end
local d1 = f( a1 )
local d2 = f( a2 )
local r
if d1.n == d2.n then
r = ( d1.s < d2.s )
else
r = ( d1.n < d2.n )
end
return r
end -- first()
local function flat( adjust )
-- Make string of specification
-- Precondition:
-- adjust -- string, number, table, with specification
-- Returns string, with specification
local r = adjust
local s = type( r )
if s == "number" then
r = mw.ustring.char( r )
elseif s == "string" then
elseif s == "table" then
local collection = {}
for k, v in pairs( r ) do
s = type( v )
if s == "number" then
table.insert( collection, mw.ustring.char( v ) )
elseif s == "string" then
table.insert( collection, v )
else
table.insert( collection, "/????/" )
end
end -- for k, v
r = table.concat( collection )
end
return r
end -- flat()
local function flip( adjust, apply )
-- Replace by set of string pattern rules
-- Precondition:
-- adjust -- string, with text
-- apply -- sequence table, with tupels { seek, set }
-- Returns string, with text
local r = adjust
local seek, set, v
for i = 1, #apply do
v = apply[ i ]
seek = flat( v[ 1 ] )
set = flat( v[ 2 ] )
apply[ i ] = { seek, set }
r = mw.ustring.gsub( r, seek, set )
end -- for i
return r
end -- flip()
local function flipper( apply, append )
-- Extend table by set of replacement rules
-- Precondition:
-- apply -- sequence table or nil, to be extended
-- append -- table, to be appended
-- Returns sequence table with replacement rules
local r = apply
local v
if type( r ) ~= "table" then
r = { }
end
for i = 1, #append do
v = append[ i ]
table.insert( r,
{ flat( v[ 1 ] ),
flat( v[ 2 ] ) } )
end -- for i
return r
end -- flipper()
local function flush( adjust )
-- Cleanup for whitespace and invisible characters
-- Precondition:
-- adjust -- string, with source text
-- Returns string, with source text
local r = adjust
local p
if r:find( "&", 1, true ) then
r = mw.text.decode( r, true )
end
p = mw.ustring.char( 91, 0x200E, 45, 0x200F,
0x202A, 45, 0x202E,
0x2066, 45, 0x2069, 93 )
r = mw.ustring.gsub( r, p, "" )
p = mw.ustring.char( 91, 0x0001, 45, 0x001F,
0x00A0,
0x2002, 45, 0x200A,
0x202F, 93 )
r = mw.ustring.gsub( r, p, " " )
return r
end -- flush()
local function focus( achieve, all )
-- Merge target specifications
-- Precondition:
-- achieve -- table, with specification
-- all -- true: include replacements
-- Postcondition:
-- specification expanded and resolved
local use = { }
local s
if type( Data.use ) ~= "table" then
Data.use = { }
end
if type( achieve.use ) == "string" then
table.insert( use, achieve.use )
elseif type( achieve.use ) == "table" then
for k, v in pairs( achieve.use ) do
table.insert( use, v )
end -- for k, v
end
achieve.use = false
for i = 1, #use do
s = use[ i ]
if Data.use[ s ] then
error( "Recursive loop: " .. s )
break -- for i
else
Data.use[ s ] = true
part = Data.trans[ s ]
if type( part ) == "table" then
if part.use then
focus( part, all )
end
if type( part.script ) == "string" and
type( achieve.script ) ~= "string" then
achieve.script = part.script
end
if all and type( part.replace ) == "table" then
achieve.replace = flipper( achieve.replace,
part.replace )
end
else
error( "Bad transclusion: " .. s )
end
end
end -- for i
end -- focus()
local function fold( above, all, at )
-- Merge base specifications
-- Precondition:
-- above -- table, with task
-- all -- true: include replacements
-- at -- string or nil, with top entry
-- Returns string, with error message, if any
local use = { }
local r, part
if type( above.use ) == "string" then
table.insert( use, above.use )
elseif type( above.use ) == "table" then
for k, v in pairs( above.use ) do
table.insert( use, v )
end -- for k, v
end
above.use = false
if at then
table.insert( use, at )
end
for i = 1, #use do
part = Data[ use[ i ] ]
if type( part ) == "table" then
if part.use then
r = fold( part, all )
end
if type( part.script ) == "string" then
Query.script = part.script
end
if all and type( part.replace ) == "table" then
Data.replace = flipper( Data.replace, part.replace )
end
if type( part.targets ) == "table" then
for k, v in pairs( part.targets ) do
Data.trans[ k ] = v
end -- for k, v
end
else
r = failure( "errCompInvalid", v )
break -- for i
end
end -- for i
return r
end -- fold()
local function foreign( achieve )
-- Execute transformation
-- Precondition:
-- achieve -- table, with specification
-- Returns table with components
-- text -- string, with transformed text
-- script -- string, with transformed text
-- error -- string, with problem
local r = { text = Query.source }
focus( achieve, true )
if type( achieve.replace ) == "table" then
r.text = flip( r.text, achieve.replace )
end
if type( achieve.script ) == "string" then
r.script = achieve.script
r.error = fidelity( r.text, achieve.script, true )
end
return r
end -- foreign()
local function forward()
-- Create template transclusion
-- Returns string, with wikisyntax text
local o = { }
local t = { }
local e, r, s, x
if Query.template[ "@" ]:find( "%s", 1, true ) then
Query.template[ "@" ] = string.format( Query.template[ "@" ],
Query.seek )
end
r = string.format( "{{%s", Query.template[ "@" ] )
e = Query.template[ "#" ]
if e then
s = Query.slang
if Query.script then
s = string.format( "%s-%s", s, Query.script )
end
t[ e ] = s
table.insert( o, e )
end
e = Query.template[ "*" ]
if e then
t[ e ] = finish( Query.source, Query.script or Query.slang )
table.insert( o, e )
end
for k, v in pairs( Query.trans ) do
if v.text then
if Query.template[ k ] then
k = Query.template[ k ]
end
t[ k ] = finish( v.text, v.script or v.slang )
table.insert( o, k )
if v.error then
x = x or ""
x = string.format( "%s %s", x, v.error )
end
end
end -- for k, v
table.sort( o, first )
for i = 1, #o do
e = o[ i ]
s = t[ e ]
if not e:match( "^%d+$" ) or
s:find( "=", 1, true ) then
s = string.format( "%s=%s", e, s )
end
r = string.format( "%s |%s", r, s )
end -- for i
r = r .. "}}"
if x then
r = r .. x
end
return r
end -- forward()
local function fresh( accept, all )
-- Build environment
-- Precondition:
-- accept -- string, language and/or script specifier
-- all -- true: include replacements
-- Postcondition:
-- Returns string, if error
local r
if accept ~= "" and type( accept ) == "string" then
Query.seek = accept
if Query.seek:match( "^%l%l%l?%-?" ) then
Query.slang = Query.seek:match( "^(%l%l%l?)$" ) or
Query.seek:match( "^(%l%l%l?)%-%u%u$" ) or
Query.seek:match( "^(%l%l%l?)%-%u%l%l%l$" )
Query.script = Query.seek:match( "^%l+%-(%u%l%l%l)$" )
if not Query.script then
local bib = Fellow()
if bib then
Query.script = bib.getLanguageScript( Query.slang )
end
end
else
Query.script = Query.seek:match( "^(%u%l%l%l)$" )
end
if not ( Query.script or Query.slang ) then
r = failure( "errBaseInvalid", Query.seek )
end
if not r then
local lucky
lucky, r = pcall( fetch )
if lucky then
if Data[ Query.seek ] then
Data.trans = { }
Query.task = Data[ Query.seek ]
if Query.task.shift and
Data[ Query.task.shift ] then
Query.seek = Query.task.shift
Query.task = Data[ Query.seek ]
end
if type( Query.task.extern ) == "string" then
Query.task.extern = { Query.task.extern }
end
if type( Query.task.extern ) == "table" then
local lucky, part
for k, v in pairs( Query.task.extern ) do
lucky, part = pcall( fetch, v )
if type( part ) == "table" then
for rk, rv in pairs( part ) do
Data[ rk ] = rv
end -- for rk, rv
else
r = failure( "errDefMissing", v )
break -- for k, v
end
end -- for k, v
end
if not r then
r = fold( Query.task, all, Query.seek )
end
else
r = failure( "errBaseUnknown", Query.seek )
end
else
r = failure( "errDefMissing" )
end
end
else
r = failure( "errBaseMissing" )
end
return r
end -- fresh()
local function furnish()
-- Execute trans series
-- Returns string, with text
local part, r
if type( Query.task ) == "table" then
Query.source = flush( Query.source )
if Data.replace then
Query.source = flip( Query.source, Data.replace )
end
r = fidelity( Query.source, Query.script )
if not r then
local s
for i = 1, #Query.targets do
s = Query.targets[ i ]
part = Data.trans[ s ]
if type( part ) == "table" then
Query.trans = Query.trans or { }
Query.trans[ s ] = foreign( part )
else
if type( s ) == "string" and s ~= "" then
s = ": " .. s
else
s = false
end
r = failure( "errTargetMissing", s )
break -- for i
end
end -- for i
end
else
r = failure( "errCompMissing", Query.seek )
end
if not r and Query.trans then
r = forward()
end
return r
end -- furnish()
Failsafe.failsafe = function ( atleast )
-- Retrieve versioning and check for compliance
-- Precondition:
-- atleast -- string, with required version or "wikidata" or "~"
-- or false
-- Postcondition:
-- Returns string -- with queried version, also if problem
-- false -- if appropriate
-- 2019-10-15
local last = ( atleast == "~" )
local since = atleast
local r
if last or since == "wikidata" then
local item = Failsafe.item
since = false
if type( item ) == "number" and item > 0 then
local entity = mw.wikibase.getEntity( string.format( "Q%d",
item ) )
if type( entity ) == "table" then
local seek = Failsafe.serialProperty or "P348"
local vsn = entity:formatPropertyValues( seek )
if type( vsn ) == "table" and
type( vsn.value ) == "string" and
vsn.value ~= "" then
if last and vsn.value == Failsafe.serial then
r = false
else
r = vsn.value
end
end
end
end
end
if type( r ) == "nil" then
if not since or since <= Failsafe.serial then
r = Failsafe.serial
else
r = false
end
end
return r
end -- Failsafe.failsafe()
TransText.fiat = function ( accept, adjust, adapt, alter )
-- Main entry
-- Precondition:
-- accept -- string, language and/or script specifier
-- adjust -- string, source text
-- adapt -- table, with required targets
-- alter -- string or nil, with JSON template spec
-- Postcondition:
-- Returns string
local r = fresh( accept, true )
if not r then
local s
if type( adjust ) == "string" then
s = mw.text.trim( adjust )
if s == "" then
r = failure( "errTextMissing" )
else
Query.source = s
end
else
r = failure( "errTextMissing" )
end
if not r then
s = type( adapt )
if s == "table" then
Query.targets = adapt
elseif s == "string" then
Query.targets = { adapt }
end
if Query.targets then
if alter then
local lucky
lucky, r = pcall( mw.text.jsonDecode,
alter )
if type( r ) == "table" then
Query.template = r
end
end
r = furnish()
else
r = failure( "errTargetMissing" )
end
end
end
return r
end -- TransText.fiat()
TransText.forwarding = function ( accept )
-- Retrieve available targets for this source
-- Precondition:
-- accept -- string, language and/or script specifier
-- Postcondition:
-- Returns table with appropriate keys,
-- or false,
-- or string with error message
local r = fresh( accept, false )
if not r and Data.trans then
r = { }
for k, v in pairs( Data.trans ) do
table.insert( r, k )
end -- for k, v
table.sort( r, first )
for i = #r - 1, 1, -1 do
if r[ i + 1 ] == r[ i ] then
table.remove( r, i + 1 )
end
end -- for i
end
return r
end -- TransText.forwarding()
-- Export
local p = { }
p.fiat = function ( frame )
-- Main task
-- 1 -- language or script code of request text
-- 2 -- request text
-- 3 -- code of first transformation
-- template -- 1 for template data
local s = mw.text.trim( frame.args[ 3 ] or "" )
local r
if s ~= "" then
local start = mw.text.trim( frame.args[ 1 ] or "" )
local source = mw.text.trim( frame.args[ 2 ] or "" )
if start ~= "" and source ~= "" then
local syntax = mw.text.trim( frame.args.template or "" )
local trans = { }
table.insert( trans, s )
for k, v in pairs( frame.args ) do
if type( k ) == "number" and k > 3 then
s = mw.text.trim( v )
if s ~= "" then
table.insert( trans, s )
end
end
end -- for k, v
Query.frame = frame
r = TransText.fiat( start, source, trans, syntax )
end
end
return r or ""
end -- p.fiat
p.forwarding = function ( frame )
-- Available targets for this source
local s = mw.text.trim( frame.args[ 1 ] or "" )
local r = TransText.forwarding( s )
if type( r ) == "table" then
if frame.args.code == "1" then
local e
for i = 1, #r do
s = r[ i ]
e = mw.html.create( "code" )
:wikitext( s )
if s:find( "-", 1, true ) then
e:css( "white-space", "nowrap" )
end
r[ i ] = tostring( e )
end -- for i
end
r = table.concat( r, " " )
else
r = ""
end
return r
end -- p.forwarding
p.from = function ( frame )
-- Available sources
local r
return r or ""
end -- p.from
p.failsafe = function ( frame )
-- Versioning interface
local s = type( frame )
local since
if s == "table" then
since = frame.args[ 1 ]
elseif s == "string" then
since = frame
end
if since then
since = mw.text.trim( since )
if since == "" then
since = false
end
end
return Failsafe.failsafe( since ) or ""
end -- p.failsafe()
p.TransText = function ()
return TransText
end -- p.TransText
return p
Content Disclaimer
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.
- The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
- There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
- It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
- Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
- Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.