User:Rical/Central modules

From mediawiki.org
This draft page and its talk must be in a better place, where you can copy it (in one or some pages).
  • This task T135845, seems enough advanced to share it.
  • That means enough defined, explicit and debug to permit at any developer to take a part of it and to work on it in coordination with others.
  • Then we can/must choose how to cooperate.
  • That means we can/must choose pages to discuss our works and changes.
  • This process also is a long term task for many central modules.
  • As a first step, on 2016-06-02, the initial developper creates this draft page to begin this process, and leave to others to take their parts of it.
  • At time, the initial developer Rical works on MW TestsCases .
  • Any developer can already #Convert a module as centralisable.


Some related pages
Draft documentation: Central modules.
Central libraries: Module:Central.
Simple examples of uses: Module:Central/Documentation
Full example: Victor_Hugo .

Task: Convert any module as central or centralisable[edit]

Scribunto permit to convert any module as central, or even centralisable before an efficient central repository exists.
That permits to use central modules in many languages, in many projects, even in many small wikis without enought helpers.
  • That provides an easier and more efficient peer review.
  • That enhanses the mean abilities of modules for a same global effort.
  • That reduces the duplication of effort for a same result.
  • That increases the mean availability of coders and helpers.
A central module can help users and helpers, in their own languages and the wiki languages, by errors, warnings, categories, reports and tests.
  • Example: display a category in the helper language and link to the category in wiki language.
  • Example: for each project and each language, choose detailed categories names or only categories "users modules errors" and "internal modules errors".
A central module must be very stable, understandable and strong against small usual misuses.
For that it permits managements of arguments, wikidata, errors, messages and modules versions.
The draft proposition for this task:task T135845 is in fr.wikisource Central modules.

What is a central module?[edit]

From actual live developments we can at least say:

It is able to use translations, in some or many languages, of its arguments names, catégories names, and errors messages that it produces.
Translations are in a /I18N submodule to not disturb it, except for minimal internal translations.
It is able to automaticly use any available translated languages.
It is able to use the local wiki language and the user language at the same time.
It can use a version management ability, at local and at central repository.
It can work at local like at central repository, for local tests without disturb central version, or for uses waiting central availability.
It is stable and contains necessary MW tests cases.
It is protected against too easy edit for a better stability.
If sought, it is able to help readers, helpers and developers in doc, edit and tests mode, showing internal documentation, reports and tests of complex basic functions.
These abilities come from one or some scribunto libraries, depending of the complexity of the module an its submomules.
Its uses of central libraries must be very simple in any simple or complex modules.
Functions verify parameters types and replace missing parameters by default values.
Functions are strong enough to accept little calling faults when non ambiguous.

How to support central modules?[edit]

Like modules in talk pages? And like phab tasks? And sharing tasks?
Use a common sharing page: Talk:Central modules?
How to name a Lua developer? Developer? Coder? Lua coder?
Use the versions management, in tests places or in final places.
The rights of Global interface editors could give global ability.
To ask in Requests for other global permissions could give global ability.
The rights of Interface editors could give global ability only from local login.
Waiting an efficient central repository, some bots could repeat validated centralisable modules in some places where active coders experiment them.

Easier, faster and stable development[edit]

Keep in one module the example of central module, and its libraries until they will be stable:
  • to easy change groups of functions in libraries, or in object,
  • to easy coordinate changes in several parts of the code,
  • to easy install and update all central libraries in a new place where use the code or where change it.
In development phase, to show the abilities of central modules, keep some languages, errors, messages, categories...
Alias of functions insure the continuity of service across change in sub-module, then in calling module, then in sub-module to delete the alias.
function tools.maini18n_lang_v_t(i18n, txt) -- Deprecated name of the function
	return tools.form_i18n_counts(i18n, txt) -- Better name or change in 
end -- Count available translations and languages
In development phase, when many functions or even some libraries are not well defined, put them in the same module and re-distribute functions and parameters.
function centre.init(frame, args_known, mode_name, options_for_modes, itemid) -- In an easier function, group some others, before change in calling module.
	tools.init_tools(frame, options_for_modes)
	centre.bindlibraries() -- Install central libraries, waiting true central libraries.
	centre.bindmodules(p)
	tools.get_arg_mode(mode_name, source_key, try_lang, args_source)
end
To try evolutions in a module or restructuration of some ones, use the versions management.
p.versions = { -- Modules dependencies. Dependencias del mĂłdulo. DĂ©pendances du module.
	versionName = "Central", versionNumber = "1.03", versionDate = "2016-02-21 23:53",
	sought = "Central01,Central 2,mathroman", -- Sought module and submodules versions
	known = " Central01,Central 2 * mathroman,mathroman3 ", -- Known module and submodules versions
}

Short story of development[edit]

  • The previous templates was based on the oldest LISP programmation langage style.
  • On 2012-04-16, Mediawiki offered Lua in Scribunto . This language is very simple to use, but very complete, all in objects, with the "meta" table to replace the words "inherited" or "class" (even sub-threads out of Mediawiki).
  • Of course then, many users began to convert each old templates in new Lua modules which was simple due to the already existing LISP-like templates.
  • But the previous French Template:Author was already a complex template, needing 6 sub-templates, see "liĂ©s".
  • On 2013-01-18, i18n tables was used to translate errors.
  • On 2013-01-25, in the Module:Author, the generic management of arguments, and the table to group their definitions, came from its large number of arguments, see "args_known".
  • On 2013-03-12, the Module:ControlArgs groups complex translations and management of arguments to support other modules to become centralisable.
  • On 2015-02-25, the Module:Author3 include the versions management for a better stability.
  • On 2016-01-30, the Module:Central convert modules in libraries.
  • On 2016-05-20, task T135845: a task propose to "Convert any module as centralizable".

State of development[edit]

In phase of development, some errors are needed to show them in some reports and to choose their better places.
Do not correct these errors, or even activate some ones.
Central translatable libraries are: centre and tools.
Each translatable library contains internal translations in english, french and spanish.
The library mathroman is a very small exemple of translatable library, only detects errors and has no mode nor options.
The centre library binds modules in sought versions management and easy translates parametrable strings.
The tools library support simple to complex modules.
Their supports are to translate, collect, manage and display views.
Translate is for arguments names from template, for images and texts on page and for categories and errors.
Waiting final true libraries, for local or central developments, the libraries and their translations can come from Module:Central and Module:Central/I18N.
Where to place the i18n translations out of the final libraries to not disturb it when translations change?
Proposition: put the centre library in Module:Library/centre/I18N.
The arguments management collects and keeps strings to translate and their parameters. Later also display lists of translated strings in right places (warning, errors, categories, categorize).
Manage arguments means also coming from wikidata, help for better argument name orthograph, auto correction of arguments names when non ambiguous, alias arguments names, verify if value is in the parametrable list of values, needed but absent, warning when twice defined, arguments descriptions.
The versions management require() adequate versions of submodules to test, following known and sought versions, like Module:Vers2.4.
This versions management reports versions used, errors, missing or replaced by normal ones... then helpers can better select and understand what happens.
Any helper of main module can select versions of its submodules from internal arguments or from template arguments.
Central libraries permit to easy generates categories, single or in group, translatable dropboxs, tables views, tests views...

Unavailable or sought abilities[edit]

on 2016-05-20

  • Central libraries are NOT stable and need to contain necessary MW tests cases.
  • For MW tests cases, we can also display the results in tableviews, like for many other tests.
  • Auto correction of arguments names when they are non ambiguous (see available levenstein).
  • Waiting the tasks debug, config arguments simulate informations depending of blocking tasks.
  • In the list of available languages, when it is large, we could display first a list of "near languages", like tools_near_languages = "fr,es,it", defined in i18n translations for each language. Others are in alphabetic order of languages codes. See tools.maini18n_languages_list() which returns "This module can translate 171 texts in 3 languages: English(en=English), español(es=Spanish), français(fr=French),".
  • For MW tests cases of the logic of centre.bindmodules(), replace existing modules by a simulation of package.loaded.
  • Make a testviewer based on MW tests cases.
  • Main options for dropbox (title, content, image) also could be in the style options.
  • Tests of multiple values arguments must be explicit.
States table of known tasks
* = ( detected state )
Used colors: , Resolved = task already completed , args = task replaced by arguments or by the module , other = other tasks
Number Status Title
Important - -
T53660 Open Detect the edit state to adapt help messages to user errors
T68051 args Give at modules the user language to display errors and categories names for him - ( detected state )
T119978 Invalid Get the own module name and last record date-time from each module
T85419 Open User groups should be exposed to Scribunto
T122752 get corrected Resolved #invoke do not record the main module in package.loaded - ( detected state )
T67507 Closed It should be possible to get entity id from page title. See EntityIdLookup::getEntityIdForTitle.
T123196 Resolved Access to item from talk page
T133498 Open Any title in wikibase can give its item id to modules - ( detected state )
Central - -
T121470 Open Central Global Repository for Templates, Lua modules, and Gadgets
T135845 Open Convert any module as central or centralisable
T52329 Stalled We need a common repository for Scribunto modules and templates
T41610 Resolved Scribunto should support global module invocations
Marginal - -
T63958 Open Use existing $dateFormats to format dates on Wikidata
T85412 Open The formatPropertyValues needs an option to format data from date-time, angle or geographic coordinates
T75460 Resolved [Story] Make Lua functions default to the user's language on multilingual wikis
Mediawiki recursive TestsCases
  • TestsCases mathroman: int2roman(2013) = MMXIII, roman2int(MMXVI) = 2016,
    • TestsCases , recursive level = 1 n/N = 13/13 , group = mathroman_groups_1
  • n/N = 1/13, countonly=13, sub_count=0, name = mathroman_groups_1_int2roman_1( , i = -11 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 2/13, countonly=14, sub_count=0, name = mathroman_groups_1_int2roman_2( , i = 0 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 3/13, countonly=15, sub_count=0, name = mathroman_groups_1_int2roman_3( , i = 12 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 4/13, countonly=16, sub_count=0, name = mathroman_groups_1_int2roman_4( , i = 17 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 5/13, countonly=17, sub_count=0, name = mathroman_groups_1_int2roman_5( , i = 18 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 6/13, countonly=18, sub_count=0, name = mathroman_groups_1_int2roman_6( , i = 19 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 7/13, countonly=19, sub_count=0, name = mathroman_groups_1_int2roman_7( , i = 111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 8/13, countonly=20, sub_count=0, name = mathroman_groups_1_int2roman_8( , i = 444 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 9/13, countonly=21, sub_count=0, name = mathroman_groups_1_int2roman_9( , i = 555 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 10/13, countonly=22, sub_count=0, name = mathroman_groups_1_int2roman_10( , i = 777 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 11/13, countonly=23, sub_count=0, name = mathroman_groups_1_int2roman_11( , i = 1111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 12/13, countonly=24, sub_count=0, name = mathroman_groups_1_int2roman_12( , i = 4999 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 13/13, countonly=25, sub_count=0, name = mathroman_groups_1_int2roman_13( , i = 5000 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • TestsCases , recursive level = 1 n/N = 8/32 , group = mathroman_groups_14
  • n/N = 1/32, countonly=32, sub_count=0, name = mathroman_groups_14_roman2int_1( , rm = -X ), , testcode = nil , argserrs =
  • n/N = 2/32, countonly=33, sub_count=0, name = mathroman_groups_14_roman2int_2( , rm = 0 ), , testcode = nil , argserrs =
  • n/N = 3/32, countonly=34, sub_count=0, name = mathroman_groups_14_roman2int_3( , rm = ), , testcode = nil , argserrs =
  • n/N = 4/32, countonly=35, sub_count=0, name = mathroman_groups_14_roman2int_4( , rm = MCXI ), , testcode = nil , argserrs =
  • n/N = 5/32, countonly=36, sub_count=0, name = mathroman_groups_14_roman2int_5( , rm = XIJ ), , testcode = nil , argserrs =
  • n/N = 6/32, countonly=37, sub_count=0, name = mathroman_groups_14_roman2int_6( , rm = XJI ), , testcode = nil , argserrs =
  • n/N = 7/32, countonly=38, sub_count=0, name = mathroman_groups_14_roman2int_7( , rm = XIA ), , testcode = nil , argserrs =
  • n/N = 8/32, countonly=39, sub_count=0, name = mathroman_groups_14_roman2int_8( , rm = VLD ), , testcode = nil , argserrs =
  • n/N = 9/32, countonly=40, sub_count=0, name = mathroman_groups_14_roman2int_9( , rm = IXC ), , testcode = nil , argserrs =
  • n/N = 10/32, countonly=41, sub_count=0, name = mathroman_groups_14_roman2int_10( , rm = MMMMCMXCIX ), , testcode = nil , argserrs =
  • n/N = 11/32, countonly=42, sub_count=0, name = mathroman_groups_14_roman2int_11( , rm = MMMMM ), , testcode = nil , argserrs =
  • n/N = 12/32, countonly=43, sub_count=0, name = mathroman_groups_14_roman2int_12( , rm = MMMMMYJXC ), , testcode = nil , argserrs =
    • TestsCases , recursive level = 2 n/N = 8/8 , group = mathroman_groups_14_roman_group_13
  • n/N = 1/8, countonly=8, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_1( , i = 1 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 2/8, countonly=9, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_2( , i = 3 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 3/8, countonly=10, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_3( , i = 6 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 4/8, countonly=11, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_4( , rm = IV ), , testcode = nil , argserrs =
  • n/N = 5/8, countonly=12, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_5( , rm = V ), , testcode = nil , argserrs =
  • n/N = 6/8, countonly=13, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_6( , rm = III ), , testcode = nil , argserrs =
  • n/N = 7/8, countonly=14, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_7( , rm = VI ), , testcode = nil , argserrs =
  • n/N = 8/8, countonly=15, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_8( , rm = I ), , testcode = nil , argserrs =
    • TestsCases , recursive level = 1 n/N = 4/4 , group = mathroman_tests_recursive_9
  • n/N = 1/4, countonly=4, sub_count=0, name = mathroman_tests_recursive_9_roman2int_1( , rm = XIJ ), , testcode = nil , argserrs =
  • n/N = 3/4, countonly=6, sub_count=0, name = mathroman_tests_recursive_9_roman2int_3( , rm = MCXI ), , testcode = nil , argserrs =
Tasks to open?
  • T00000: Add module and library types in scribunto ?
  • T00001: Sorted tableview do not sort date-time, in template and in module.
  • T00002: In a dropbox after \n* the content is after the box. Better define the case. Insert "\n------" before correct that. Try that out of fr.wikisource, in test2 or mediawiki...
  • T00003: bindI18N() after bindmodules to protect sought translatios against un-sought ones.
  • T00011: Sorted tableview do not sort date-time
  • T00012: In a dropbox after \n* the content is not inside the box. Better define the case. Insert "\n------" before to correct that.
  • T00013: Insert and mask structured datas and errors in resulting wikitext for bots. In xml or json or template style.
  • T00014: Display changes in test_init() arguments, in a dropbox.
  • T00015: Convert some groups of functions as new objects types: tableview with its headers and options, luatable() and its luatablecount(), dropbox() and dropdownfunc() and their options, get{} output from centre.get_module_and_time() for modules and libraries.

Blocked tasks[edit]

task T41610: Scribunto should support global module invocations
task T127354: Consider helping some smaller Wikipedias' communities
task T122086: RFC: Sharing templates and modules between wikis - poor man's version (investigation)
task T89598: Convert Template:Authority_control to Lua and use Wikidata

Blocking tasks[edit]

Some blocking tasks are detected by the module itself.

{{#invoke:Central | doc | tools_tasks_table_report_title }}

Mediawiki recursive TestsCases
  • TestsCases mathroman: int2roman(2013) = MMXIII, roman2int(MMXVI) = 2016,
    • TestsCases , recursive level = 1 n/N = 13/13 , group = mathroman_groups_1
  • n/N = 1/13, countonly=13, sub_count=0, name = mathroman_groups_1_int2roman_1( , i = -11 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 2/13, countonly=14, sub_count=0, name = mathroman_groups_1_int2roman_2( , i = 0 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 3/13, countonly=15, sub_count=0, name = mathroman_groups_1_int2roman_3( , i = 12 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 4/13, countonly=16, sub_count=0, name = mathroman_groups_1_int2roman_4( , i = 17 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 5/13, countonly=17, sub_count=0, name = mathroman_groups_1_int2roman_5( , i = 18 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 6/13, countonly=18, sub_count=0, name = mathroman_groups_1_int2roman_6( , i = 19 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 7/13, countonly=19, sub_count=0, name = mathroman_groups_1_int2roman_7( , i = 111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 8/13, countonly=20, sub_count=0, name = mathroman_groups_1_int2roman_8( , i = 444 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 9/13, countonly=21, sub_count=0, name = mathroman_groups_1_int2roman_9( , i = 555 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 10/13, countonly=22, sub_count=0, name = mathroman_groups_1_int2roman_10( , i = 777 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 11/13, countonly=23, sub_count=0, name = mathroman_groups_1_int2roman_11( , i = 1111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 12/13, countonly=24, sub_count=0, name = mathroman_groups_1_int2roman_12( , i = 4999 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 13/13, countonly=25, sub_count=0, name = mathroman_groups_1_int2roman_13( , i = 5000 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • TestsCases , recursive level = 1 n/N = 8/32 , group = mathroman_groups_14
  • n/N = 1/32, countonly=32, sub_count=0, name = mathroman_groups_14_roman2int_1( , rm = -X ), , testcode = nil , argserrs =
  • n/N = 2/32, countonly=33, sub_count=0, name = mathroman_groups_14_roman2int_2( , rm = 0 ), , testcode = nil , argserrs =
  • n/N = 3/32, countonly=34, sub_count=0, name = mathroman_groups_14_roman2int_3( , rm = ), , testcode = nil , argserrs =
  • n/N = 4/32, countonly=35, sub_count=0, name = mathroman_groups_14_roman2int_4( , rm = MCXI ), , testcode = nil , argserrs =
  • n/N = 5/32, countonly=36, sub_count=0, name = mathroman_groups_14_roman2int_5( , rm = XIJ ), , testcode = nil , argserrs =
  • n/N = 6/32, countonly=37, sub_count=0, name = mathroman_groups_14_roman2int_6( , rm = XJI ), , testcode = nil , argserrs =
  • n/N = 7/32, countonly=38, sub_count=0, name = mathroman_groups_14_roman2int_7( , rm = XIA ), , testcode = nil , argserrs =
  • n/N = 8/32, countonly=39, sub_count=0, name = mathroman_groups_14_roman2int_8( , rm = VLD ), , testcode = nil , argserrs =
  • n/N = 9/32, countonly=40, sub_count=0, name = mathroman_groups_14_roman2int_9( , rm = IXC ), , testcode = nil , argserrs =
  • n/N = 10/32, countonly=41, sub_count=0, name = mathroman_groups_14_roman2int_10( , rm = MMMMCMXCIX ), , testcode = nil , argserrs =
  • n/N = 11/32, countonly=42, sub_count=0, name = mathroman_groups_14_roman2int_11( , rm = MMMMM ), , testcode = nil , argserrs =
  • n/N = 12/32, countonly=43, sub_count=0, name = mathroman_groups_14_roman2int_12( , rm = MMMMMYJXC ), , testcode = nil , argserrs =
    • TestsCases , recursive level = 2 n/N = 8/8 , group = mathroman_groups_14_roman_group_13
  • n/N = 1/8, countonly=8, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_1( , i = 1 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 2/8, countonly=9, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_2( , i = 3 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 3/8, countonly=10, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_3( , i = 6 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 4/8, countonly=11, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_4( , rm = IV ), , testcode = nil , argserrs =
  • n/N = 5/8, countonly=12, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_5( , rm = V ), , testcode = nil , argserrs =
  • n/N = 6/8, countonly=13, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_6( , rm = III ), , testcode = nil , argserrs =
  • n/N = 7/8, countonly=14, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_7( , rm = VI ), , testcode = nil , argserrs =
  • n/N = 8/8, countonly=15, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_8( , rm = I ), , testcode = nil , argserrs =
    • TestsCases , recursive level = 1 n/N = 4/4 , group = mathroman_tests_recursive_9
  • n/N = 1/4, countonly=4, sub_count=0, name = mathroman_tests_recursive_9_roman2int_1( , rm = XIJ ), , testcode = nil , argserrs =
  • n/N = 3/4, countonly=6, sub_count=0, name = mathroman_tests_recursive_9_roman2int_3( , rm = MCXI ), , testcode = nil , argserrs =

Important support tasks[edit]

task T53660: Detect the edit state to adapt help messages to user errors.
  • To show edit or test mode only in edit state.
task T68051: Get the user language to help admins to maintain a module or a template
  • Permit to use the same module in many languages in many projects. This enlarge the use of modules in many more small wikis. This also enhanse the mean abilities of modules for a same global effort.
  • Help helpers, from large wikis in their own langages, to help small wikis in other languages. Example: display a category in the helper language and link to the category in wiki language.
task T119978: Get the own module name and last record date-time from each module
  • This task is necessary to reduce human errors:
  • to rightly collect /I18N translations,
  • and for a more confident versions management.
  • search this task id below for details.
task T122752: #invoke seems do not record the module
  • This task is a true bug which impacts the versions management.
  • But the centre library correct it for the main module. Other modules come by require() and are not impacted.
  • In most other uses, this bug has no impact.
See
  • tools.task_T122752_get_state() -- Detect T122752 : #invoke seems do not record the module
  • tools.task_T122752_correct_once() -- Debug T122752 : #invoke seems do not record the module

Central repository tasks[edit]

  • These tasks impact the final stage of true central usage.
  • But the full development of central libraries is possible without central repository.
  • And the use of central libraries is possible in any local wiki with exactly the same modules, and only new i18n tranlations.
task T121470: Central Global Repository for Templates, Lua modules, and Gadgets
task T52329: We need a common repository for Scribunto modules and templates
task T41610: Scribunto should support global module invocations

Marginal tasks[edit]

  • These tasks are interesting to optimize somefunctions but have no link to any central aspects.
task T48160: Lua: Allow using labels in mw.wikibase.entity.formatPropertyValues
task T63958: Use existing $dateFormats to format dates on Wikidata
task T85412: The formatPropertyValues needs an option to format data from date-time, angle or geographic coordinates
task T75460: [Story] Make Luafunctions default to the user's language on multilingual wikis
task T85419: User groups should be exposed to Scribunto ( This permit to adapt errors and warning for administrators or modules coders )

Documentations examples[edit]

{{#invoke:Central|read|itemid=Q8023}}

{{{1}}}
, label = Nelson Mandela , , birthyear = 1918 , deathyear = 2013 , int2roman = nil , roman2int = nil , int2roman = nil
This module can translate 208 sentences in 3 languages: English(en=English), español(es=Spanish), français(fr=French),


{{#invoke:Central|doc|tools_tasks_table_report_title}} ?

States table of known tasks
* = ( detected state )
Used colors: , Resolved = task already completed , args = task replaced by arguments or by the module , other = other tasks
Number Status Title
Important - -
T53660 Open Detect the edit state to adapt help messages to user errors
T68051 args Give at modules the user language to display errors and categories names for him - ( detected state )
T119978 Invalid Get the own module name and last record date-time from each module
T85419 Open User groups should be exposed to Scribunto
T122752 get corrected Resolved #invoke do not record the main module in package.loaded - ( detected state )
T67507 Closed It should be possible to get entity id from page title. See EntityIdLookup::getEntityIdForTitle.
T123196 Resolved Access to item from talk page
T133498 Open Any title in wikibase can give its item id to modules - ( detected state )
Central - -
T121470 Open Central Global Repository for Templates, Lua modules, and Gadgets
T135845 Open Convert any module as central or centralisable
T52329 Stalled We need a common repository for Scribunto modules and templates
T41610 Resolved Scribunto should support global module invocations
Marginal - -
T63958 Open Use existing $dateFormats to format dates on Wikidata
T85412 Open The formatPropertyValues needs an option to format data from date-time, angle or geographic coordinates
T75460 Resolved [Story] Make Lua functions default to the user's language on multilingual wikis
Mediawiki recursive TestsCases
  • TestsCases mathroman: int2roman(2013) = MMXIII, roman2int(MMXVI) = 2016,
    • TestsCases , recursive level = 1 n/N = 13/13 , group = mathroman_groups_1
  • n/N = 1/13, countonly=13, sub_count=0, name = mathroman_groups_1_int2roman_1( , i = -11 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 2/13, countonly=14, sub_count=0, name = mathroman_groups_1_int2roman_2( , i = 0 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 3/13, countonly=15, sub_count=0, name = mathroman_groups_1_int2roman_3( , i = 12 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 4/13, countonly=16, sub_count=0, name = mathroman_groups_1_int2roman_4( , i = 17 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 5/13, countonly=17, sub_count=0, name = mathroman_groups_1_int2roman_5( , i = 18 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 6/13, countonly=18, sub_count=0, name = mathroman_groups_1_int2roman_6( , i = 19 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 7/13, countonly=19, sub_count=0, name = mathroman_groups_1_int2roman_7( , i = 111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 8/13, countonly=20, sub_count=0, name = mathroman_groups_1_int2roman_8( , i = 444 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 9/13, countonly=21, sub_count=0, name = mathroman_groups_1_int2roman_9( , i = 555 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 10/13, countonly=22, sub_count=0, name = mathroman_groups_1_int2roman_10( , i = 777 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 11/13, countonly=23, sub_count=0, name = mathroman_groups_1_int2roman_11( , i = 1111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 12/13, countonly=24, sub_count=0, name = mathroman_groups_1_int2roman_12( , i = 4999 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 13/13, countonly=25, sub_count=0, name = mathroman_groups_1_int2roman_13( , i = 5000 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • TestsCases , recursive level = 1 n/N = 8/32 , group = mathroman_groups_14
  • n/N = 1/32, countonly=32, sub_count=0, name = mathroman_groups_14_roman2int_1( , rm = -X ), , testcode = nil , argserrs =
  • n/N = 2/32, countonly=33, sub_count=0, name = mathroman_groups_14_roman2int_2( , rm = 0 ), , testcode = nil , argserrs =
  • n/N = 3/32, countonly=34, sub_count=0, name = mathroman_groups_14_roman2int_3( , rm = ), , testcode = nil , argserrs =
  • n/N = 4/32, countonly=35, sub_count=0, name = mathroman_groups_14_roman2int_4( , rm = MCXI ), , testcode = nil , argserrs =
  • n/N = 5/32, countonly=36, sub_count=0, name = mathroman_groups_14_roman2int_5( , rm = XIJ ), , testcode = nil , argserrs =
  • n/N = 6/32, countonly=37, sub_count=0, name = mathroman_groups_14_roman2int_6( , rm = XJI ), , testcode = nil , argserrs =
  • n/N = 7/32, countonly=38, sub_count=0, name = mathroman_groups_14_roman2int_7( , rm = XIA ), , testcode = nil , argserrs =
  • n/N = 8/32, countonly=39, sub_count=0, name = mathroman_groups_14_roman2int_8( , rm = VLD ), , testcode = nil , argserrs =
  • n/N = 9/32, countonly=40, sub_count=0, name = mathroman_groups_14_roman2int_9( , rm = IXC ), , testcode = nil , argserrs =
  • n/N = 10/32, countonly=41, sub_count=0, name = mathroman_groups_14_roman2int_10( , rm = MMMMCMXCIX ), , testcode = nil , argserrs =
  • n/N = 11/32, countonly=42, sub_count=0, name = mathroman_groups_14_roman2int_11( , rm = MMMMM ), , testcode = nil , argserrs =
  • n/N = 12/32, countonly=43, sub_count=0, name = mathroman_groups_14_roman2int_12( , rm = MMMMMYJXC ), , testcode = nil , argserrs =
    • TestsCases , recursive level = 2 n/N = 8/8 , group = mathroman_groups_14_roman_group_13
  • n/N = 1/8, countonly=8, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_1( , i = 1 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 2/8, countonly=9, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_2( , i = 3 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 3/8, countonly=10, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_3( , i = 6 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 4/8, countonly=11, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_4( , rm = IV ), , testcode = nil , argserrs =
  • n/N = 5/8, countonly=12, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_5( , rm = V ), , testcode = nil , argserrs =
  • n/N = 6/8, countonly=13, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_6( , rm = III ), , testcode = nil , argserrs =
  • n/N = 7/8, countonly=14, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_7( , rm = VI ), , testcode = nil , argserrs =
  • n/N = 8/8, countonly=15, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_8( , rm = I ), , testcode = nil , argserrs =
    • TestsCases , recursive level = 1 n/N = 4/4 , group = mathroman_tests_recursive_9
  • n/N = 1/4, countonly=4, sub_count=0, name = mathroman_tests_recursive_9_roman2int_1( , rm = XIJ ), , testcode = nil , argserrs =
  • n/N = 3/4, countonly=6, sub_count=0, name = mathroman_tests_recursive_9_roman2int_3( , rm = MCXI ), , testcode = nil , argserrs =


{{#invoke:Central|doc|tools_wikidata_arbitrary_test_title|Q535}}

Test of Wikidata arbitrary access
  • Wikidata for another Title: Q535, Victor Hugo ( 1802 - 1885 ) ⊁  Datas from Wikidata , 376 properties.
  • Sought properties: , sitelink = nil , label = Victor Hugo , deathyear = 1885 , country = France , description = nil , birthyear = 1802 , itemid2 = Q535 , itemid = Q535
  • Wikidata for another Title: Q8023, Nelson Mandela ( 1918 - 2013 ) ⊁  Datas from Wikidata , 245 properties.
  • Sought properties: , sitelink = nil , label = Nelson Mandela , deathyear = 2013 , country = South Africa , description = nil , birthyear = 1918 , itemid2 = Q8023 , itemid = Q8023
Mediawiki recursive TestsCases
  • TestsCases mathroman: int2roman(2013) = MMXIII, roman2int(MMXVI) = 2016,
    • TestsCases , recursive level = 1 n/N = 13/13 , group = mathroman_groups_1
  • n/N = 1/13, countonly=13, sub_count=0, name = mathroman_groups_1_int2roman_1( , i = -11 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 2/13, countonly=14, sub_count=0, name = mathroman_groups_1_int2roman_2( , i = 0 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 3/13, countonly=15, sub_count=0, name = mathroman_groups_1_int2roman_3( , i = 12 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 4/13, countonly=16, sub_count=0, name = mathroman_groups_1_int2roman_4( , i = 17 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 5/13, countonly=17, sub_count=0, name = mathroman_groups_1_int2roman_5( , i = 18 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 6/13, countonly=18, sub_count=0, name = mathroman_groups_1_int2roman_6( , i = 19 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 7/13, countonly=19, sub_count=0, name = mathroman_groups_1_int2roman_7( , i = 111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 8/13, countonly=20, sub_count=0, name = mathroman_groups_1_int2roman_8( , i = 444 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 9/13, countonly=21, sub_count=0, name = mathroman_groups_1_int2roman_9( , i = 555 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 10/13, countonly=22, sub_count=0, name = mathroman_groups_1_int2roman_10( , i = 777 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 11/13, countonly=23, sub_count=0, name = mathroman_groups_1_int2roman_11( , i = 1111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 12/13, countonly=24, sub_count=0, name = mathroman_groups_1_int2roman_12( , i = 4999 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 13/13, countonly=25, sub_count=0, name = mathroman_groups_1_int2roman_13( , i = 5000 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • TestsCases , recursive level = 1 n/N = 8/32 , group = mathroman_groups_14
  • n/N = 1/32, countonly=32, sub_count=0, name = mathroman_groups_14_roman2int_1( , rm = -X ), , testcode = nil , argserrs =
  • n/N = 2/32, countonly=33, sub_count=0, name = mathroman_groups_14_roman2int_2( , rm = 0 ), , testcode = nil , argserrs =
  • n/N = 3/32, countonly=34, sub_count=0, name = mathroman_groups_14_roman2int_3( , rm = ), , testcode = nil , argserrs =
  • n/N = 4/32, countonly=35, sub_count=0, name = mathroman_groups_14_roman2int_4( , rm = MCXI ), , testcode = nil , argserrs =
  • n/N = 5/32, countonly=36, sub_count=0, name = mathroman_groups_14_roman2int_5( , rm = XIJ ), , testcode = nil , argserrs =
  • n/N = 6/32, countonly=37, sub_count=0, name = mathroman_groups_14_roman2int_6( , rm = XJI ), , testcode = nil , argserrs =
  • n/N = 7/32, countonly=38, sub_count=0, name = mathroman_groups_14_roman2int_7( , rm = XIA ), , testcode = nil , argserrs =
  • n/N = 8/32, countonly=39, sub_count=0, name = mathroman_groups_14_roman2int_8( , rm = VLD ), , testcode = nil , argserrs =
  • n/N = 9/32, countonly=40, sub_count=0, name = mathroman_groups_14_roman2int_9( , rm = IXC ), , testcode = nil , argserrs =
  • n/N = 10/32, countonly=41, sub_count=0, name = mathroman_groups_14_roman2int_10( , rm = MMMMCMXCIX ), , testcode = nil , argserrs =
  • n/N = 11/32, countonly=42, sub_count=0, name = mathroman_groups_14_roman2int_11( , rm = MMMMM ), , testcode = nil , argserrs =
  • n/N = 12/32, countonly=43, sub_count=0, name = mathroman_groups_14_roman2int_12( , rm = MMMMMYJXC ), , testcode = nil , argserrs =
    • TestsCases , recursive level = 2 n/N = 8/8 , group = mathroman_groups_14_roman_group_13
  • n/N = 1/8, countonly=8, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_1( , i = 1 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 2/8, countonly=9, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_2( , i = 3 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 3/8, countonly=10, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_3( , i = 6 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 4/8, countonly=11, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_4( , rm = IV ), , testcode = nil , argserrs =
  • n/N = 5/8, countonly=12, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_5( , rm = V ), , testcode = nil , argserrs =
  • n/N = 6/8, countonly=13, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_6( , rm = III ), , testcode = nil , argserrs =
  • n/N = 7/8, countonly=14, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_7( , rm = VI ), , testcode = nil , argserrs =
  • n/N = 8/8, countonly=15, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_8( , rm = I ), , testcode = nil , argserrs =
    • TestsCases , recursive level = 1 n/N = 4/4 , group = mathroman_tests_recursive_9
  • n/N = 1/4, countonly=4, sub_count=0, name = mathroman_tests_recursive_9_roman2int_1( , rm = XIJ ), , testcode = nil , argserrs =
  • n/N = 3/4, countonly=6, sub_count=0, name = mathroman_tests_recursive_9_roman2int_3( , rm = MCXI ), , testcode = nil , argserrs =

  • Convert a module as centralisable[edit]

    Translate arguments, errors, categories...[edit]

    Translate arguments names (and their descriptions), errors, categories, title...
    p.i18n.en = { -- English
    	mode 						= "mode", -- All arguments must be translated in all languages to operate.
    	mode_descr					= "Type of use of the module or template: read, edit, doc, test.", -- Describe the argument for documentation.
    	options 					= "options",
    	options_descr				= "Options to form the module or model result.",
    	firstname					= 'firstname', -- Other argument and description
    	firstname_descr				= "First name. Please specify to correct the sort key.",
    	mathroman_J_before_end_err	= "character J before the end", -- Example of error.
    	mathroman_dig2romtest_title = "Test from digital to roman numbers", -- Example of title of a group of tests.
    	tools_language_cat			= 'Speaking %1', -- Example of category.
    	tools_date_to_part_call_cat	= "Module with internal error", -- Several errors are grouped in a same category, defined at translation level.
    	tools_needed_to_verify		= "(required, to be checked)", -- In the list of arguments, an argument is needed
    }
    

    Define arguments[edit]

    • All arguments must be translated in all languages to operate.
    p.args_known = { -- Table of the definitions of all known arguments at module level.
    	birthyear =		{typ = "dat", need = 0, keyword = "birthyear", prop = "P569", format = "year"},
    	firstname =		{typ = "dat", need = 0, keyword = "firstname"},
    }
    

    Initialize a module[edit]

    p.options_for_modes = { -- default options
    	read	= " noerr ",
    	doc		= " noerr nobox nocat ",
    	edit	= " : catview docview docdef docline docsrc docdata ",
    	tests	= " : catview docview docdef docline docsrc docdata tests ",
    	-- Option nocat means "Do not categorize and do not show categories."
    }
    
    function p.read(frame) -- Forms the text to read by users.
    	local res = ""
    	centre.init(frame, p.args_known, "read", p.options_for_modes)
    	tools.args_final = p.interact_args_final(tools.args_import) -- Interactions between arguments
    	res = res .. p.form_result() -- forms the resulting wikitext
    	return res
    end -- function p.read(frame)
    

    Minimal centalisable module[edit]

    A module without interface can form translated errors or categories in any function, without any p.interface(frame) functions.
    It can also use translated arguments and/or form report to display later if sought.
    The centre library and the mathroman library are in this case.
    Any module using central library can contain, or none, internal translations in english and some other languages.
    Minimal example:
    p.i18n.en = { -- Define translations of arguments names, categories names, and errors messages to produce.
    	birthyear = "birthyear", -- example
    	centre_luatable_counts = "%1 variables, %2 functions, %3 sub-tables", -- example
    } -- p.i18n.en
    
    p.args_known = { -- Define all known arguments at the main module level.
    	birthyear = {typ = "dat", need = 0, list = 2, keyword = "birthyear", prop = "P569", format = "year"},
    } -- p.args_known
    
    p.options_for_modes = { -- default options
    	read	= " noerr ",
    }
    
    function p.read(frame) -- Forms the text to read for users.
    	local res = ""
    	centre.init(frame, p.args_known, "read", p.options_for_modes) -- Default init from the centre library.
    	res = res .. "Hello world !" -- Forms the resulting wikitext
    	return res
    end -- function p.read(frame)
    

    Modes and options[edit]

    Really used options come from p.options_for_modes and from options arguments.
    Modes are composed of options to choose what and how to display. Default modes:
    p.options_for_modes = { -- default options
    	read	= " noerr ",
    	doc		= " noerr nobox nocat ",
    	edit	= " : catview docview docdef docline docsrc docdata ",
    	tests	= " : catview docview docdef docline docsrc docdata tests ",
    	-- Option nocat means "Do not categorize and do not show categories."
    }
    
    function p.read(frame) -- Normal use for simple readers of pages
    	local res = ""
    	centre.init(frame, p.args_known, "read", p.options_for_modes) -- Default init from the centre library.
    	res = res .. try.form_result() -- Forms the resulting wikitext
    end
    
    function p.doc(frame) -- To include some pieces of documentations directly from the module in its template or module documentation page.
    	centre.init(frame, p.args_known, "doc", p.options_for_modes) -- Default init from the centre library.
    	res = res .. tools.dropdownfunc(select, "tools_similar_args_test_title", tools.similar_args_test)
    end
    
    function p.edit(frame) -- To support the user to modify arguments in case of errors. To light support of helpers in their own laguages.
    	centre.init(frame, p.args_known, "edit", p.options_for_modes) -- Default init from the centre library.
    	res = res .. formDocBox() -- A panel to help users when they dit the use of a template or module.
    	-- With a dropbox for helpers, displaying availables languages, versions used, number of admins in a wiki...
    	res = res .. try.form_result() -- Forms the resulting wikitext
    end
    
    function p.tests(frame) -- The most extended support for helpers.
    	centre.init(frame, p.args_known, "tests", p.options_for_modes) -- Default init from the centre library.
    	res = res .. formDocBox() -- A panel to help users when they dit the use of a template or module.
    	-- With a dropbox for helpers, displaying availables languages, versions used, number of admins in a wiki...
    	res = res .. try.form_result() -- Forms the resulting wikitext
    	res = res .. try.testsview("allwaysview")
    end
    
    p.options_for_modes = { -- default options					for anyother mode
    	read	= " noerr ",
    	doc		= " noerr nobox nocat ",
    	edit	= " : catview docview docdef docline docsrc docdata ",
    	tests	= " : catview docview docdef docline docsrc docdata tests ",
    	anyother = " noerr other noother ", -- Other mode, to manage in code.
    }
    

    Versions management[edit]

    Each centralisable main module can start with a definition of alternative versions of its sub-modules.
    Then its versions management is available.
    p.versions = { -- Modules dependencies. Dependencias del mĂłdulo. DĂ©pendances du module.
    	versionName = "Main", versionNumber = "1.03", versionDate = "2016-04-27 23:23",
    	sought = "Main, Box 2, Item.3", -- Sought module and submodules versions
    	known = " Main,Main2 * Box,Box 2 * Item,Item.2,Item.3 ", -- Known module and submodules versions
    }
    
    Template or invoke arguments can replace soughtversions and knownversions to try them without record, or in a test template.
    In known versions, the first of each group of versions is the normal one and can replace any other if not available.
    The versions management require() adequate versions of submodules to test, following known and sought versions, like Module:Vers2.4.
    This versions management reports versions: used, errors, missing or replaced by normal ones... then helpers can better select and understand what happens.
    Any helper of main module can select versions of its submodules from internal arguments or from template arguments.
    When the developer copies or rename this file in a new version, he can forget to adapt that definition and then disturb the versions management.
    To reduce this risk, each module need to know its own name.
    To document the version date-time, we need that for each module or sub-module.
    See the task task T119978: Get the own module name and last record date-time from each module

    {{#invoke:Central | doc | dockey = tools_bindmodules_test_title | itemid = Q535 }}

    Test for management of modules versions
    • tools.versions_management_test : The selector = Box3, Group, Item1 means: check these modules versions among those available.
    • loaded_vers : Table of all loaded modules, or simulation.
    • Simulate existing versions:
    Sought versions Used versions ACTUAL: Errors in the active module
    ,Central, ,, vers.request
    sought: Central in the main module: Central

    known: ,Central,
    loaded list: ,Central,
    comment:
    Sought versions Used versions SIMULATION: Errors in the active module
    ,Box, ,Box, normal modules
    sought: Box in the main module: Box

    known: ,Box,
    loaded list: ,Box,
    comment: normal module for Box, with alias like : local Box = require("Box")
    ,Box, ,Box,
    Box/I18N,
    normal with /I18N
    sought: Box in the main module: Box

    known: ,Box,
    loaded list: ,Box, Box/I18N,
    comment: I18N translations for Box
    ,Box2, ,Box,
    Box/I18N,
    Box2,
    Box2/I18N,
    normal replace known alternate
    sought: Box2 in the main module: Box2

    ⊁ The module Box replaces the missing sub-module in the main module Box2.
    known: ,Box, Box2,
    loaded list: ,Box, Box/I18N, Box2, Box2/I18N,
    comment: alternate version module for Box
    ,Box, ,Box2,
    Box2/I18N,
    Box3,
    Box3/I18N,
    missing actual module
    sought: Box in the main module: Box2

    ⊁ The module Box misses in the main module Box2.
    ⊁ The module Box is unknown in the main module Box2.
    ⊁ The module Box2 replaces the missing sub-module in the main module Box2.
    ⊁ The module Box3 replaces the missing sub-module in the main module Box2.
    known: ,Box2, Box3,
    loaded list: ,Box2, Box2/I18N, Box3, Box3/I18N,
    comment: I18N translations without basic module. Form an alert.
    ,Group, ,Group,
    Group/I18N,
    normal sub-module
    sought: Group in the main module: Box

    known: ,Group,
    loaded list: ,Group, Group/I18N,
    comment: normal module for Group
    ,Box,
    Group,
    ,Box, unknown sought version
    sought: Box,Group in the main module: Box

    ⊁ The module Group misses in the main module Box.
    ⊁ The module Group is unknown in the main module Box.
    known: ,Box,
    loaded list: ,Box,
    comment: Mask this to test missing sought version
    ,Box,
    Group,
    ,Box, sub-module not exists
    sought: Box,Group in the main module: Box

    known: ,Box * Group,
    loaded list: ,Box,
    comment: I18N translations for the normal module Group
    ,Box,
    Group2,
    ,Box,
    Box/I18N,
    Box2,
    Box2/I18N,
    Group,
    Group/I18N,
    Group2,
    Group2/I18N,
    normal sub-module with normal /18N
    sought: Box,Group2 in the main module: Box3

    ⊁ The module Box2 replaces the missing sub-module in the main module Box3.
    ⊁ The module Group replaces the missing sub-module in the main module Box3.
    known: ,Box, Box2 * Group, Group2,
    loaded list: ,Box, Box/I18N, Box2, Box2/I18N, Group, Group/I18N, Group2, Group2/I18N,
    comment: normal alternate sub-module Group for Group2
    ,Box,
    Group2,
    ,Box,
    Box/I18N,
    Box2,
    Box2/I18N,
    Group,
    Group/I18N,
    Group2,
    Group2/I18N,
    unknown module for /18N sub-module
    sought: Box,Group2 in the main module: Box3

    ⊁ The module Box2 replaces the missing sub-module in the main module Box3.
    ⊁ The module Group replaces the missing sub-module in the main module Box3.
    known: ,Box, Box2 * Group, Group2,
    loaded list: ,Box, Box/I18N, Box2, Box2/I18N, Group, Group/I18N, Group2, Group2/I18N,
    comment: normal alternate sub-module Group for Group2
    ,Box,
    Group2,
    ,Box/I18N,
    Box2,
    Box2/I18N,
    Group,
    Group/I18N,
    Group2,
    Group2/I18N,
    missing module Box for /18N sub-module
    sought: Box,Group2 in the main module: Box3

    ⊁ The module Box2 replaces the missing sub-module in the main module Box3.
    ⊁ The module Group replaces the missing sub-module in the main module Box3.
    known: ,Box, Box2 * Group, Group2,
    loaded list: ,Box/I18N, Box2, Box2/I18N, Group, Group/I18N, Group2, Group2/I18N,
    comment: normal alternate sub-module Group for Group2
    ,Box, ,Box, not central module, without i18n
    sought: Box in the main module: Jocker

    known: ,Box,
    loaded list: ,Box,
    comment: Any module can have no i18n table.
    ,Jocker.2, ,, unknown and not sought actual module
    sought: Jocker.2 in the main module: Jocker

    known: ,Jocker.2,
    loaded list: ,Box,
    comment: Any module can be outside of the central system.
    Sought versions Used versions SIMULATION: Errors in the active module
    • The table below simulates loaded modules for behind tests cases.
    Title Version Date i18n Translations / Languages
    Box Box 2015-12-02 02:02 table normal module for Box, with alias like : local Box = require("Box")
    Box/I18N Box 2016-05-07 18:36 table I18N translations for Box
    Box3 Box2 2016-05-07 11:11 table alternate version module for Box
    Box2/I18N Box2 2016-05-07 19:19 table I18N translations without basic module. Form an alert.
    Group Box table normal module for Group
    Group4 Box 2015-12-11 11:11 table Mask this to test missing sought version
    Group/I18N Box 2016-05-07 22:2 table I18N translations for the normal module Group
    Group2 Box3 2016-05-07 05:05 table normal alternate sub-module Group for Group2
    Group2 Box3 2016-05-07 05:05 table normal alternate sub-module Group for Group2
    Group2 Box3 2016-05-07 05:05 table normal alternate sub-module Group for Group2
    Jocker Jocker 2015-12-21 11:33 nil Any module can have no i18n table.
    Jocker Jocker 2015-12-21 11:33 table Any module can be outside of the central system.
    • , Number of versions simulated: = 12
    Mediawiki recursive TestsCases
  • TestsCases mathroman: int2roman(2013) = MMXIII, roman2int(MMXVI) = 2016,
    • TestsCases , recursive level = 1 n/N = 13/13 , group = mathroman_groups_1
  • n/N = 1/13, countonly=13, sub_count=0, name = mathroman_groups_1_int2roman_1( , i = -11 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 2/13, countonly=14, sub_count=0, name = mathroman_groups_1_int2roman_2( , i = 0 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 3/13, countonly=15, sub_count=0, name = mathroman_groups_1_int2roman_3( , i = 12 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 4/13, countonly=16, sub_count=0, name = mathroman_groups_1_int2roman_4( , i = 17 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 5/13, countonly=17, sub_count=0, name = mathroman_groups_1_int2roman_5( , i = 18 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 6/13, countonly=18, sub_count=0, name = mathroman_groups_1_int2roman_6( , i = 19 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 7/13, countonly=19, sub_count=0, name = mathroman_groups_1_int2roman_7( , i = 111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 8/13, countonly=20, sub_count=0, name = mathroman_groups_1_int2roman_8( , i = 444 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 9/13, countonly=21, sub_count=0, name = mathroman_groups_1_int2roman_9( , i = 555 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 10/13, countonly=22, sub_count=0, name = mathroman_groups_1_int2roman_10( , i = 777 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 11/13, countonly=23, sub_count=0, name = mathroman_groups_1_int2roman_11( , i = 1111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 12/13, countonly=24, sub_count=0, name = mathroman_groups_1_int2roman_12( , i = 4999 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 13/13, countonly=25, sub_count=0, name = mathroman_groups_1_int2roman_13( , i = 5000 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • TestsCases , recursive level = 1 n/N = 8/32 , group = mathroman_groups_14
  • n/N = 1/32, countonly=32, sub_count=0, name = mathroman_groups_14_roman2int_1( , rm = -X ), , testcode = nil , argserrs =
  • n/N = 2/32, countonly=33, sub_count=0, name = mathroman_groups_14_roman2int_2( , rm = 0 ), , testcode = nil , argserrs =
  • n/N = 3/32, countonly=34, sub_count=0, name = mathroman_groups_14_roman2int_3( , rm = ), , testcode = nil , argserrs =
  • n/N = 4/32, countonly=35, sub_count=0, name = mathroman_groups_14_roman2int_4( , rm = MCXI ), , testcode = nil , argserrs =
  • n/N = 5/32, countonly=36, sub_count=0, name = mathroman_groups_14_roman2int_5( , rm = XIJ ), , testcode = nil , argserrs =
  • n/N = 6/32, countonly=37, sub_count=0, name = mathroman_groups_14_roman2int_6( , rm = XJI ), , testcode = nil , argserrs =
  • n/N = 7/32, countonly=38, sub_count=0, name = mathroman_groups_14_roman2int_7( , rm = XIA ), , testcode = nil , argserrs =
  • n/N = 8/32, countonly=39, sub_count=0, name = mathroman_groups_14_roman2int_8( , rm = VLD ), , testcode = nil , argserrs =
  • n/N = 9/32, countonly=40, sub_count=0, name = mathroman_groups_14_roman2int_9( , rm = IXC ), , testcode = nil , argserrs =
  • n/N = 10/32, countonly=41, sub_count=0, name = mathroman_groups_14_roman2int_10( , rm = MMMMCMXCIX ), , testcode = nil , argserrs =
  • n/N = 11/32, countonly=42, sub_count=0, name = mathroman_groups_14_roman2int_11( , rm = MMMMM ), , testcode = nil , argserrs =
  • n/N = 12/32, countonly=43, sub_count=0, name = mathroman_groups_14_roman2int_12( , rm = MMMMMYJXC ), , testcode = nil , argserrs =
    • TestsCases , recursive level = 2 n/N = 8/8 , group = mathroman_groups_14_roman_group_13
  • n/N = 1/8, countonly=8, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_1( , i = 1 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 2/8, countonly=9, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_2( , i = 3 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 3/8, countonly=10, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_3( , i = 6 ), , testcode = nil , argserrs = mathroman_null_value_err-0
  • n/N = 4/8, countonly=11, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_4( , rm = IV ), , testcode = nil , argserrs =
  • n/N = 5/8, countonly=12, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_5( , rm = V ), , testcode = nil , argserrs =
  • n/N = 6/8, countonly=13, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_6( , rm = III ), , testcode = nil , argserrs =
  • n/N = 7/8, countonly=14, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_7( , rm = VI ), , testcode = nil , argserrs =
  • n/N = 8/8, countonly=15, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_8( , rm = I ), , testcode = nil , argserrs =
    • TestsCases , recursive level = 1 n/N = 4/4 , group = mathroman_tests_recursive_9
  • n/N = 1/4, countonly=4, sub_count=0, name = mathroman_tests_recursive_9_roman2int_1( , rm = XIJ ), , testcode = nil , argserrs =
  • n/N = 3/4, countonly=6, sub_count=0, name = mathroman_tests_recursive_9_roman2int_3( , rm = MCXI ), , testcode = nil , argserrs =
  • Translations management[edit]

    Any translation must not involuntarily disturb an other and we must insure that this cannot happens, especially in new modules or libraries.
    For this need we can/must start any translation key with the name of the module or library.
    An alternative version can modify any translation of the normal version.
    A main module can modify any translation from any submodule to adapt it to a new context.
    A /I18N submodule can adjust or correct any translation from a normal or new version.

    Then the centre.bindmodules(p)function follows these rules:

    • starts with the libraries translations,
    • starts with the internal translations,
    • then add or mix translations from normal /I18N,
    • then add or mix translations from the /I18N alternative versions,
    • continue with the modules translations,
    • starts with the internal translations,
    • then add or mix translations from normal /I18N,
    • then add or mix translations from the /I18N alternative versions.
    In doc or test mode, a report display missing or modified translations.
    To reduce errors risks in the binding of translations, we need to base each /I18N sub-module name on the name of each module itself.
    See the task task T119978: Get the own module name and last record date-time from each module

    {{#invoke:Central | doc | dockey = tools_missing_translations_title | itemid = Q535 }}

    Translations missings and changes in i18n tables:
    • Comparer les langues : es/fr,
    • Comparer les langues : fr/en,
      ⊁ Internal Error: Module missing i18n translation for the argument tools_auto_val_warning_2_msg

      ⊁ Internal Error: There are 1 missings in 213 translations.
    • Translated languages: Langues traduites : , Langue : es , Langue : fr , Langue : en
    • There are 3 tables of translations in these languages : es, fr, en,
    • Same example without translation for a test case : tools_languages_nbr_and_list-3-es, fr, en,


    • transdiff_report: Compare all differences of translations:
    Language Key Previous translation New translation Module
    Mediawiki recursive TestsCases
    • TestsCases mathroman: int2roman(2013) = MMXIII, roman2int(MMXVI) = 2016,
      • TestsCases , recursive level = 1 n/N = 13/13 , group = mathroman_groups_1
    • n/N = 1/13, countonly=13, sub_count=0, name = mathroman_groups_1_int2roman_1( , i = -11 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 2/13, countonly=14, sub_count=0, name = mathroman_groups_1_int2roman_2( , i = 0 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 3/13, countonly=15, sub_count=0, name = mathroman_groups_1_int2roman_3( , i = 12 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 4/13, countonly=16, sub_count=0, name = mathroman_groups_1_int2roman_4( , i = 17 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 5/13, countonly=17, sub_count=0, name = mathroman_groups_1_int2roman_5( , i = 18 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 6/13, countonly=18, sub_count=0, name = mathroman_groups_1_int2roman_6( , i = 19 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 7/13, countonly=19, sub_count=0, name = mathroman_groups_1_int2roman_7( , i = 111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 8/13, countonly=20, sub_count=0, name = mathroman_groups_1_int2roman_8( , i = 444 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 9/13, countonly=21, sub_count=0, name = mathroman_groups_1_int2roman_9( , i = 555 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 10/13, countonly=22, sub_count=0, name = mathroman_groups_1_int2roman_10( , i = 777 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 11/13, countonly=23, sub_count=0, name = mathroman_groups_1_int2roman_11( , i = 1111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 12/13, countonly=24, sub_count=0, name = mathroman_groups_1_int2roman_12( , i = 4999 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 13/13, countonly=25, sub_count=0, name = mathroman_groups_1_int2roman_13( , i = 5000 ), , testcode = nil , argserrs = mathroman_null_value_err-0
      • TestsCases , recursive level = 1 n/N = 8/32 , group = mathroman_groups_14
    • n/N = 1/32, countonly=32, sub_count=0, name = mathroman_groups_14_roman2int_1( , rm = -X ), , testcode = nil , argserrs =
    • n/N = 2/32, countonly=33, sub_count=0, name = mathroman_groups_14_roman2int_2( , rm = 0 ), , testcode = nil , argserrs =
    • n/N = 3/32, countonly=34, sub_count=0, name = mathroman_groups_14_roman2int_3( , rm = ), , testcode = nil , argserrs =
    • n/N = 4/32, countonly=35, sub_count=0, name = mathroman_groups_14_roman2int_4( , rm = MCXI ), , testcode = nil , argserrs =
    • n/N = 5/32, countonly=36, sub_count=0, name = mathroman_groups_14_roman2int_5( , rm = XIJ ), , testcode = nil , argserrs =
    • n/N = 6/32, countonly=37, sub_count=0, name = mathroman_groups_14_roman2int_6( , rm = XJI ), , testcode = nil , argserrs =
    • n/N = 7/32, countonly=38, sub_count=0, name = mathroman_groups_14_roman2int_7( , rm = XIA ), , testcode = nil , argserrs =
    • n/N = 8/32, countonly=39, sub_count=0, name = mathroman_groups_14_roman2int_8( , rm = VLD ), , testcode = nil , argserrs =
    • n/N = 9/32, countonly=40, sub_count=0, name = mathroman_groups_14_roman2int_9( , rm = IXC ), , testcode = nil , argserrs =
    • n/N = 10/32, countonly=41, sub_count=0, name = mathroman_groups_14_roman2int_10( , rm = MMMMCMXCIX ), , testcode = nil , argserrs =
    • n/N = 11/32, countonly=42, sub_count=0, name = mathroman_groups_14_roman2int_11( , rm = MMMMM ), , testcode = nil , argserrs =
    • n/N = 12/32, countonly=43, sub_count=0, name = mathroman_groups_14_roman2int_12( , rm = MMMMMYJXC ), , testcode = nil , argserrs =
      • TestsCases , recursive level = 2 n/N = 8/8 , group = mathroman_groups_14_roman_group_13
    • n/N = 1/8, countonly=8, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_1( , i = 1 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 2/8, countonly=9, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_2( , i = 3 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 3/8, countonly=10, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_3( , i = 6 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 4/8, countonly=11, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_4( , rm = IV ), , testcode = nil , argserrs =
    • n/N = 5/8, countonly=12, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_5( , rm = V ), , testcode = nil , argserrs =
    • n/N = 6/8, countonly=13, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_6( , rm = III ), , testcode = nil , argserrs =
    • n/N = 7/8, countonly=14, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_7( , rm = VI ), , testcode = nil , argserrs =
    • n/N = 8/8, countonly=15, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_8( , rm = I ), , testcode = nil , argserrs =
      • TestsCases , recursive level = 1 n/N = 4/4 , group = mathroman_tests_recursive_9
    • n/N = 1/4, countonly=4, sub_count=0, name = mathroman_tests_recursive_9_roman2int_1( , rm = XIJ ), , testcode = nil , argserrs =
    • n/N = 3/4, countonly=6, sub_count=0, name = mathroman_tests_recursive_9_roman2int_3( , rm = MCXI ), , testcode = nil , argserrs =

    Structures and guidelines[edit]

    In development phase keep some light errors to show how reports form errors.
    The central code must be strong with or without central repository, libraries, known bugs and weak use.
    Then central functions must specialy verify their arguments, run only once if needed, tested by tests cases, and tests shown for users.

    Process of arguments and translations[edit]

    -- Process of arguments and translations along their transformations :
    	tools.args_known = {} -- Known arguments, at main module level
    	tools.args_invoke = {} -- Invoke arguments, at {{#invoke: ... }} level
    	tools.args_template = {} -- Template arguments, at {{Template| ... }} level
    	tools.args_source = {} -- Source arguments = args_template + args_invoke
    	tools.args_config = {} -- Config arguments, without translation, for helpers
    	tools.args_unknown = {} -- Unknown arguments
    	tools.args_wikidata = {} -- Wikidata arguments, from Wikibase
    	tools.args_import = {} -- Import arguments
    	tools.args_final = p.interact_args_final() -- Final arguments, after interactions between them
    	tools.args_selected = {} -- Selected arguments, in some modules
    	tools.wiki_translations = {} -- Wiki translations
    	tools.user_translations = {} -- User translations
    	tools.errors_list = {} -- Errors list
    	tools.categories_list = {} -- Categories lists
    
    Steps in arguments process:
    tools.args_known : The main module defines all arguments, and they all must have translations in all availables languages.
    tools.args_source : The source arguments come from template, else from #invoke, for each argument.
    tools.args_config : Memorize direct configuration arguments.
    tools.args_wikidata : An argument can come from wikidata if its definition have a wikidata property like prop = "P21".
    The priority in origin of an argument is always: first the template, else the { {#invoke:module, else the internal interaction between arguments in the module, else the internal default value in the module.
    tools.args_config : The config arguments come without translations from source arguments. Translations are identical in all available languages.
    p.args_known = { -- Table of the definitions of all known arguments at module level.
    	birthyear = {				-- Key of the argument.
    		--
    		keyword = "birthyear",	-- The keyword is the same as Key to identify the argument in some cases.
    		syn = 1,				-- A synonym of an argument defined in the args_known table.
    		keyword = "birthyear2",	-- For a synonym, the keyword identify the referal argument.
    		-- A synonym can be another argument. Then interact_args_final(args_import) mixes them.
    		--
    		typ = "dat",			-- The type "dat" is the basic type of arguments.
    		typ = "config",			-- The type "config" groups direct arguments from tools.args_source, without translation.
    		--
    		need = 1,				-- If need == 1 the argument can be automatic.
    		need = 2,				-- If need == 2 the argument must come from the template or wikidata.
    		--
    		prop = "P569",			-- Wikidata property to automatic import an argument, if available.
    		format = "year",		-- Extract the year from a Wikidata property.
    	},
    }
    tools.args_wikidata = tools.import_wikidata(tools.args_known)
    tools.args_import = tools.import_arguments() -- Import arguments from all origins, normaly in p.init().
    tools.args_final = p.interact_args_final(tools.args_import) -- Special interactions between arguments in the main module, even special in a mode.
    

    {{#invoke:Central | doc | tools_list_all_args_title }}

    Mediawiki recursive TestsCases
    • TestsCases mathroman: int2roman(2013) = MMXIII, roman2int(MMXVI) = 2016,
      • TestsCases , recursive level = 1 n/N = 13/13 , group = mathroman_groups_1
    • n/N = 1/13, countonly=13, sub_count=0, name = mathroman_groups_1_int2roman_1( , i = -11 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 2/13, countonly=14, sub_count=0, name = mathroman_groups_1_int2roman_2( , i = 0 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 3/13, countonly=15, sub_count=0, name = mathroman_groups_1_int2roman_3( , i = 12 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 4/13, countonly=16, sub_count=0, name = mathroman_groups_1_int2roman_4( , i = 17 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 5/13, countonly=17, sub_count=0, name = mathroman_groups_1_int2roman_5( , i = 18 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 6/13, countonly=18, sub_count=0, name = mathroman_groups_1_int2roman_6( , i = 19 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 7/13, countonly=19, sub_count=0, name = mathroman_groups_1_int2roman_7( , i = 111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 8/13, countonly=20, sub_count=0, name = mathroman_groups_1_int2roman_8( , i = 444 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 9/13, countonly=21, sub_count=0, name = mathroman_groups_1_int2roman_9( , i = 555 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 10/13, countonly=22, sub_count=0, name = mathroman_groups_1_int2roman_10( , i = 777 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 11/13, countonly=23, sub_count=0, name = mathroman_groups_1_int2roman_11( , i = 1111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 12/13, countonly=24, sub_count=0, name = mathroman_groups_1_int2roman_12( , i = 4999 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 13/13, countonly=25, sub_count=0, name = mathroman_groups_1_int2roman_13( , i = 5000 ), , testcode = nil , argserrs = mathroman_null_value_err-0
      • TestsCases , recursive level = 1 n/N = 8/32 , group = mathroman_groups_14
    • n/N = 1/32, countonly=32, sub_count=0, name = mathroman_groups_14_roman2int_1( , rm = -X ), , testcode = nil , argserrs =
    • n/N = 2/32, countonly=33, sub_count=0, name = mathroman_groups_14_roman2int_2( , rm = 0 ), , testcode = nil , argserrs =
    • n/N = 3/32, countonly=34, sub_count=0, name = mathroman_groups_14_roman2int_3( , rm = ), , testcode = nil , argserrs =
    • n/N = 4/32, countonly=35, sub_count=0, name = mathroman_groups_14_roman2int_4( , rm = MCXI ), , testcode = nil , argserrs =
    • n/N = 5/32, countonly=36, sub_count=0, name = mathroman_groups_14_roman2int_5( , rm = XIJ ), , testcode = nil , argserrs =
    • n/N = 6/32, countonly=37, sub_count=0, name = mathroman_groups_14_roman2int_6( , rm = XJI ), , testcode = nil , argserrs =
    • n/N = 7/32, countonly=38, sub_count=0, name = mathroman_groups_14_roman2int_7( , rm = XIA ), , testcode = nil , argserrs =
    • n/N = 8/32, countonly=39, sub_count=0, name = mathroman_groups_14_roman2int_8( , rm = VLD ), , testcode = nil , argserrs =
    • n/N = 9/32, countonly=40, sub_count=0, name = mathroman_groups_14_roman2int_9( , rm = IXC ), , testcode = nil , argserrs =
    • n/N = 10/32, countonly=41, sub_count=0, name = mathroman_groups_14_roman2int_10( , rm = MMMMCMXCIX ), , testcode = nil , argserrs =
    • n/N = 11/32, countonly=42, sub_count=0, name = mathroman_groups_14_roman2int_11( , rm = MMMMM ), , testcode = nil , argserrs =
    • n/N = 12/32, countonly=43, sub_count=0, name = mathroman_groups_14_roman2int_12( , rm = MMMMMYJXC ), , testcode = nil , argserrs =
      • TestsCases , recursive level = 2 n/N = 8/8 , group = mathroman_groups_14_roman_group_13
    • n/N = 1/8, countonly=8, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_1( , i = 1 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 2/8, countonly=9, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_2( , i = 3 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 3/8, countonly=10, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_3( , i = 6 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 4/8, countonly=11, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_4( , rm = IV ), , testcode = nil , argserrs =
    • n/N = 5/8, countonly=12, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_5( , rm = V ), , testcode = nil , argserrs =
    • n/N = 6/8, countonly=13, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_6( , rm = III ), , testcode = nil , argserrs =
    • n/N = 7/8, countonly=14, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_7( , rm = VI ), , testcode = nil , argserrs =
    • n/N = 8/8, countonly=15, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_8( , rm = I ), , testcode = nil , argserrs =
      • TestsCases , recursive level = 1 n/N = 4/4 , group = mathroman_tests_recursive_9
    • n/N = 1/4, countonly=4, sub_count=0, name = mathroman_tests_recursive_9_roman2int_1( , rm = XIJ ), , testcode = nil , argserrs =
    • n/N = 3/4, countonly=6, sub_count=0, name = mathroman_tests_recursive_9_roman2int_3( , rm = MCXI ), , testcode = nil , argserrs =

    Arguments properties[edit]

    {{#invoke:Central | doc | tools_args_known_structure_title }}

    Mediawiki recursive TestsCases
    • TestsCases mathroman: int2roman(2013) = MMXIII, roman2int(MMXVI) = 2016,
      • TestsCases , recursive level = 1 n/N = 13/13 , group = mathroman_groups_1
    • n/N = 1/13, countonly=13, sub_count=0, name = mathroman_groups_1_int2roman_1( , i = -11 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 2/13, countonly=14, sub_count=0, name = mathroman_groups_1_int2roman_2( , i = 0 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 3/13, countonly=15, sub_count=0, name = mathroman_groups_1_int2roman_3( , i = 12 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 4/13, countonly=16, sub_count=0, name = mathroman_groups_1_int2roman_4( , i = 17 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 5/13, countonly=17, sub_count=0, name = mathroman_groups_1_int2roman_5( , i = 18 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 6/13, countonly=18, sub_count=0, name = mathroman_groups_1_int2roman_6( , i = 19 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 7/13, countonly=19, sub_count=0, name = mathroman_groups_1_int2roman_7( , i = 111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 8/13, countonly=20, sub_count=0, name = mathroman_groups_1_int2roman_8( , i = 444 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 9/13, countonly=21, sub_count=0, name = mathroman_groups_1_int2roman_9( , i = 555 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 10/13, countonly=22, sub_count=0, name = mathroman_groups_1_int2roman_10( , i = 777 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 11/13, countonly=23, sub_count=0, name = mathroman_groups_1_int2roman_11( , i = 1111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 12/13, countonly=24, sub_count=0, name = mathroman_groups_1_int2roman_12( , i = 4999 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 13/13, countonly=25, sub_count=0, name = mathroman_groups_1_int2roman_13( , i = 5000 ), , testcode = nil , argserrs = mathroman_null_value_err-0
      • TestsCases , recursive level = 1 n/N = 8/32 , group = mathroman_groups_14
    • n/N = 1/32, countonly=32, sub_count=0, name = mathroman_groups_14_roman2int_1( , rm = -X ), , testcode = nil , argserrs =
    • n/N = 2/32, countonly=33, sub_count=0, name = mathroman_groups_14_roman2int_2( , rm = 0 ), , testcode = nil , argserrs =
    • n/N = 3/32, countonly=34, sub_count=0, name = mathroman_groups_14_roman2int_3( , rm = ), , testcode = nil , argserrs =
    • n/N = 4/32, countonly=35, sub_count=0, name = mathroman_groups_14_roman2int_4( , rm = MCXI ), , testcode = nil , argserrs =
    • n/N = 5/32, countonly=36, sub_count=0, name = mathroman_groups_14_roman2int_5( , rm = XIJ ), , testcode = nil , argserrs =
    • n/N = 6/32, countonly=37, sub_count=0, name = mathroman_groups_14_roman2int_6( , rm = XJI ), , testcode = nil , argserrs =
    • n/N = 7/32, countonly=38, sub_count=0, name = mathroman_groups_14_roman2int_7( , rm = XIA ), , testcode = nil , argserrs =
    • n/N = 8/32, countonly=39, sub_count=0, name = mathroman_groups_14_roman2int_8( , rm = VLD ), , testcode = nil , argserrs =
    • n/N = 9/32, countonly=40, sub_count=0, name = mathroman_groups_14_roman2int_9( , rm = IXC ), , testcode = nil , argserrs =
    • n/N = 10/32, countonly=41, sub_count=0, name = mathroman_groups_14_roman2int_10( , rm = MMMMCMXCIX ), , testcode = nil , argserrs =
    • n/N = 11/32, countonly=42, sub_count=0, name = mathroman_groups_14_roman2int_11( , rm = MMMMM ), , testcode = nil , argserrs =
    • n/N = 12/32, countonly=43, sub_count=0, name = mathroman_groups_14_roman2int_12( , rm = MMMMMYJXC ), , testcode = nil , argserrs =
      • TestsCases , recursive level = 2 n/N = 8/8 , group = mathroman_groups_14_roman_group_13
    • n/N = 1/8, countonly=8, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_1( , i = 1 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 2/8, countonly=9, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_2( , i = 3 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 3/8, countonly=10, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_3( , i = 6 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 4/8, countonly=11, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_4( , rm = IV ), , testcode = nil , argserrs =
    • n/N = 5/8, countonly=12, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_5( , rm = V ), , testcode = nil , argserrs =
    • n/N = 6/8, countonly=13, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_6( , rm = III ), , testcode = nil , argserrs =
    • n/N = 7/8, countonly=14, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_7( , rm = VI ), , testcode = nil , argserrs =
    • n/N = 8/8, countonly=15, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_8( , rm = I ), , testcode = nil , argserrs =
      • TestsCases , recursive level = 1 n/N = 4/4 , group = mathroman_tests_recursive_9
    • n/N = 1/4, countonly=4, sub_count=0, name = mathroman_tests_recursive_9_roman2int_1( , rm = XIJ ), , testcode = nil , argserrs =
    • n/N = 3/4, countonly=6, sub_count=0, name = mathroman_tests_recursive_9_roman2int_3( , rm = MCXI ), , testcode = nil , argserrs =

    They can be needed, synonym, limited to some values ... typical examples:

    	language =	{keyword = "language", typ = "dat", need = 0, prop = "P103", }, -- Simple argument, with wikidata property.
    	--
    	[1] =		{keyword = "mode", typ = "sys", need = 0, syn = 2, }, -- Synonym or alias of an argument defined by position.
    	--
    	c =			{keyword = "c", typ = "dat", need = 0, syn = 1, }, -- Synonym or alias arguments.
    	options =	{keyword = "c", typ = "dat", need = 0, syn = 2, }, -- Synonym or alias arguments.
    	--
    	-- Argument limited to some values.
    	region =	{keyword = "region", typ = "dat", need = 0, -- like Simple argument
    		arg_values = "region_values", key_values = "other,china,india,century" }, -- arg_values translation key for 
    	region_values	= "autre,chine,inde,siĂšcle", -- i18n french translations for region argument.
    	region_values	= 'otros,china,india,siglo', -- i18n spanish translations for region argument.
    	--
    	-- Argument and its description.
    	options			= 'options', -- Arguments can be described for documentation in tests or in doc mode.
    	options_descr	= 'Options to add with mode options.',
    

    Config support arguments[edit]

    They drive directly support aspects, without translations:

    	userlang =	"", -- user language for i18n translations.
    	wikilang =	"", -- wiki language for i18n translations.
    	--
    	mode_name = tools.args_source.mode
    	options =	"",
    	c =	"",
    	--
    	selectversions =	"", -- Helpers can change sought versions in edit or tests modes.
    	allversions =	"", -- Helpers can change known versions in edit or tests modes.
    	--
    	dockey =	"", -- key of document to display in doc mode.
    	id =	"Q535", -- wikidata element to display in doc mode.
    	entityid =	"Q535", -- wikidata element to display in doc mode.
    	--
    	local doc1_doc = tools.args_source.dockey or tools.args_source[1]
    	local doc1_id = tools.args_source.entityid or tools.args_source.id or tools.args_source[2]
    

    Translations texts keys[edit]

    They follow these guideline. That enable to group them in documentations for errors, categories and other:

    	library_ident_words_err			= "parametrable string", -- <b>Basic</b> structure: key = "text".
    	--
    	tools_auto_val_warning_msg		= "Verify the automatic argument: %1 = <b>%2</b>.", -- Example of <b>message</b>.
    	tools_lang_not_exist_err		= "Error: The language <b>%1</b> is not available.", -- Example of <b>error</b>.
    	tools_lang_table_err_cat		= "Module with internal error", -- Example of <b>category</b>.
    	tools_page_tests_h3_title		= "Tests of this page", -- Example of <b>title</b> of DropBox, or anywhere.
    	tools_loaded_modules_headers	= "Title, Version, Date, I18N, Translations / Languages", -- Example of <b>headers in a tableview</b>.
    	tools_versionsmanagement_report	= "Versions management report", -- Example of <b>title of report</b>.
    	--
    	options							= 'options', -- Argument to describe.
    	options_descr					= 'Options to add with mode options.', -- <b>Description</b> for an argument.
    	-- The key of the description is the key of the argument, plus <b>_descr</b>.
    

    Central libraries[edit]

    How to name central libraries ?[edit]

    How to distribute functions in one or some libraries ?
    How to name also all the functions of these libraries ?
    The centre library mainly binds modules. Eventual names:
    • centre as international noun and to support to move in a central place.
    • center as USA english noun and to support to move in a central place.
    • central as the place in the middle.
    • centralize as support to move in the middle.
    • centralizer as support to move in the middle.
    The tools library mainly extends the translation service and translatable usual viewers. Eventual names:
    • centretools as tools for the centre library.
    • centraltools as available tools shared in the central space.
    • translatabletools as available tools shared in the central space.
    Whe could make a viewer or viewers library to group:
    • tableviewer for table of raws and columns.
    • dropbox and dropdownfunc with title, content and style options.
    • cat_add for parametrable and bilingual categories, and to group their list.
    • msg_add for parametrable messages, and to group their list.
    • luatable for counts and structures of luatable.

    centre library[edit]

    The centre library binds modules in sought versions and their translations.

    centre.new_library[edit]

    Record a library in package.loaded from a table object.
    	centre.new_library(name, library, options)
    

    centre.bindlibraries[edit]

    	function centre.bindlibraries() -- Install central libraries, waiting true central libraries.
    

    centre.bindmodules[edit]

    Bind all modules, versions and translations. Cumulate in centre.maini18n all translations from i18n tables from modules.
    	res = res .. centre.bindmodules(p) -- Example of use in the main module.
    	res = res .. centre.bindmodules() -- Without (p), bindmodules find itself the main module.
    	res = res .. centre.bindmodules(other) -- The main module can choose another main module.
    

    centre.get_module_and_time[edit]

    This function can create a module and/or collect and complete data on a module or a library.
    This code roughly describe it:
    	local get = centre.get_module_and_time("Module:Example")
    	-- Get the module from require("Module:Example") but not fails if it not exists.
    	-- Then get datas on the module and report them.
    	
    	local get = centre.get_module_and_time("Module:Example", module)
    	-- Record the module with the title "Module:Example" in package.loaded.
    	-- Then get datas on the module and report them.
    	
    	local get = centre.get_module_and_time(title, module) -- Get a descriptor of one loaded object
    	-- After that, get is roughly equivalent to:
    	
    	get.title = title -- Like "Module:Example" for a module
    	get.module = module -- The module code itself (compiled).
    	get.isNil = not module
    	get.isLoaded = true and package.loaded[title]
    	get.isFunction = (type(module) == "function")
    	get.isTable = (type(module) == "table")
    	get.isModule = true if the title looklikes to "Module:Example"
    	get.isLibrary = true if the title looklikes to "example"
    	get.i18n = module.i18n -- translations tables from the module
    	get.versions = module.versions -- descriptor for the versions management {sought, known...}
    	get.hasi18n = true and module.i18n
    	get.versionName = title without "Module:", but perhaps with "/I18N"
    	get.isI18N = true if title include "/I18N"
    	get.lessI18N = title without "/I18N"
    	get.simplename = title without "Module:" and without "/I18N"
    	if get.isModule then
    		get.lessI18N = title without "/I18N"
    	--	get.versionI18N = "Module:Example/I18N" -- eventual /I18N module to search
    		get.subI18N = get.title .. "/I18N" -- eventual sub-module "/I18N"
    		get.revistamp = "20160501122359" -- The compact record date-time of the module. Here for 01 May 2016 at 12:23:59
    	end
    	if get.isLibrary then
    		get.lessI18N = title looklikes to "example" without "/I18N"
    	--	get.versionI18N = "Module:Library/example/I18N" -- eventual /I18N module to search
    		get.subI18N = centre.ModuleNS .. "Library/" .. get.title .. "/I18N" -- eventual sub-module "/I18N"
    		get.revistamp = "20010101000000" -- Default compact date-time for all libraries on 1st January 2001 00:00:00. Or perhaps true date-time.
    	end
    

    tools library[edit]

    Internalfunctions to implement mainfunctions are not described.

    tools.str_vars[edit]

    	tools.str_vars(ref, v1, v2, v3, v4, v5, v6, v7, v8, v9)
    	tools.str_vars("Module with internal error") -- example with text
    	tools.str_vars("tools_luatable_counts", tot_vars, tot_func, tot_tabs) -- example with key.
    	tools.str_vars("%1 variables, %2functions, %3 sub-tables", 30, 10, 4) -- example with text and values.
    

    Result in a parametrable string based on ref.

    • If ref is a key of translatable string in i18n table, it is first translated.
    • If ref is not a translatable key, thisfunction uses it like translated.
    • If the translated string contains %1 to %9 thisfunction replaces them by v1 to v9 respectively, after thisfunction converts them in strings.
    • If ref is any other string, thefunction return it as is.

    This is roughly equivalent to:

    function tools.str_vars(ref, v1, v2, v3, v4, v5, v6, v7, v8, v9)
    	ref = tostring(ref)
    	if translations[ref] then wt = tostring(translations[ref])
    	elseif ref then wt = tostring(ref)
    	else wt = tostring("noref") end
    	v1 = v1 or " 1"
    	...
    	v9 = v9 or " 9"
    	if v1 then wt = string.gsub(wt, "%%1", tostring(v1) ) end
    	...
    	if v9 then wt = string.gsub(wt, "%%9", tostring(v9) ) end
    	return tostring(wt)
    end
    

    tools.str_test_case[edit]

    This is a first step to work on tests_cases. See also mathroman.tests_cases
    This function for test case do not translate but convert it like in: forest_t_trees_b_birds-7-trees-1000-birds
    This is better for tests cases:
    • Then tests cases depend of values but not of the languages.
    • Different translations have different keys but can have a same text.
    This is roughly equivalent to:
    function tools.str_test_case(ref, v1, v2, v3, v4, v5, v6, v7, v8, v9) -- add v1 to v9 to the ref
    	return ref .. "-" .. v1 .. "-" .. v2 .. "-" .. v3 ...
    	-- which looklikes in:
    	return "forest_t_trees_b_birds-7-trees-1000-birds"
    end
    
    For tests cases search : class ClassNameTest extends Scribunto_LuaEngineTestBase

    tools.is_in[edit]

    Returns true if the word is in the text, even inside another word. Else return false.
    	function tools.is_in(word, text) -- return true if the word is in the text. Else return false.
    

    This is roughly equivalent to:

    function tools.is_in(word, text)
    	return string.find(text, word)
    end
    

    tools.is_in_sp[edit]

    Returns true if the word is in the text, beetwen spaces or separators, not inside another word. Else return false.
    This function is in centre which use it to find versions in list.

    This is roughly equivalent to:

    function tools.is_in_sp(word, text, sep)
    	sep = sep or " "
    	return string.find(sep .. text .. sep, sep .. word .. sep)
    end
    

    tools.cat_add[edit]

    tools.cat_add(ref, v1, v2, v3, v4, v5, v6, v7, v8, v9)
    
    Record a category in categories_list, parametrable like tools.str_vars().

    tools.catGroup[edit]

    Generate categories from plural values in only one string argument divided by comas.
    function tools.catGroup(groupCat, groupList)
    
    Record a groupCat group of categories in categories_list.
    Each part is translatable like in tools.str_vars(one of parts of groupList).
    Example wich give Category:Country France , Category:Country Italy
    tools.catGroup("Country %1", "France,Italy")
    

    This is roughly equivalent to:

    function tools.cat_add(ref, v1, v2, v3, v4, v5)
    
    For each part of ref divided by a coma.

    tools.err_add[edit]

    tools.err_add(ref, v1, v2, v3, v4, v5, v6, v7, v8, v9)
    
    Returns a error, parametrable like tools.str_vars().
    Record also these errors in errors_list.

    tools.msg_add[edit]

    tools.msg_add(ref, v1, v2, v3, v4, v5, v6, v7, v8, v9)
    
    Returns a message, parametrable like tools.str_vars().
    Record also these messages in errors_list.

    tools.errors_lister[edit]

    tools.errors_lister()
    
    Returns the list of all recorded messages first, then all errors.
    Does not return duplicates errors or messages.

    tools.Th tableview[edit]

    That could become the tableview object.
    function tools.Th(t) -- Header of a tableview
    function tools.Tc(t) -- Header of one column of a tableview
    function tools.Tr(t) -- Row of a tableviewtableview
    function tools.Td(t) -- Data cell of a tableview
    function tools.Te(t) -- End of a tableview
    
    	-- Example of sortable tableview (but after sort, intermediate headers are not at the right place)
    	t = t .. tools.Th("wikitable sortable") .. tools.Tc("Name") .. tools.Tc("Year") .. tools.Tc("Size") -- First headers
    	t = t .. tools.Tr() .. tools.Td("Sara") .. tools.Td("1983") .. tools.Td("167")
    	t = t .. tools.Tr() .. tools.Tc("Surname") .. tools.Tc("Epoch") .. tools.Tc("Size maxi") -- Intermediate headers
    	t = t .. tools.Tr() .. tools.Td("Alan") .. tools.Td("1987") .. tools.Td("175")
    	t = t .. tools.Te()
    

    tools.dropbox[edit]

    dropbox, documentation in a single dropbox, series of dropboxes.

    options to select

    tools.dropbox(title, content, boxstyle)
    
    Returns a dropbox with parametrable title and style.
    The optional boxstyle parameter is a table containing options to define the style of the dropbox.

    tools.dropdownfunc[edit]

    tools.dropdownfunc(select, title, content, ...)
    
    Like tools.dropbox().
    • This function forms the dropbox if select is "allwaysview" or "enforcerun" or true or the title key before translation.
    If the function fails the dropbox displays <red>INTERNAL ERROR</red>, to protect the displaying of the rest of the page.
    Then a developer can replace (select, with ("enforcerun", for this box. Then he/she can debug the code error. See examples below.
    The content parameter can be a string or a function followed by any number of its parameters.
    Options for the dropbox are in a table identified by one of its contents:
    boxstyle = { ..., boxstyle = "boxstyle", ...}
    
    Options and their default values are:
    tools.maini18n_languages_list()
    	alignT = alignT or "left", -- align
    	alignB = alignB or "left", -- align
    	margin_all = margin_all or "0px", -- margin
    	margin_bottom = margin_bottom or "1em", -- margin-bottom
    	width = width or "99%", -- width
    	border_radius = border_radius or "0", -- border-radius
    	text_color = text_color or "black", -- color
    	background_color = background_color or "#FFFFFF", -- background-color
    	border_color = border_color or "#AAAAAA", -- border-color
    	height = height or "1.6em", -- height
    	label = "&#x25bc; &nbsp; /&#x25b6; &nbsp; ", --	 = "Unwrap/Wrap",
    
    Options are not but also could be title, content, image.
    Example of dropbox style options:

    {{#invoke:Central | doc | dockey = tools_options_from_mode_title | itemid = Q535 }}

    Test options from modes
    options_from_mode_test:
    - , normal = noerr
    - , read = noerr
    - , edit =  : catview docview docdef docline docsrc docdata
    - , tests =  : catview docview docdef docline docsrc docdata tests
    - , doc1 = nobox noerr nocat
    Mode List of options noerr value docview value tests value
    options_from_mode_test:
    read noerr true
    edit : catview docview docdef docline docsrc docdata true
    tests : catview docview docdef docline docsrc docdata tests true true
    Mediawiki recursive TestsCases
    • TestsCases mathroman: int2roman(2013) = MMXIII, roman2int(MMXVI) = 2016,
      • TestsCases , recursive level = 1 n/N = 13/13 , group = mathroman_groups_1
    • n/N = 1/13, countonly=13, sub_count=0, name = mathroman_groups_1_int2roman_1( , i = -11 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 2/13, countonly=14, sub_count=0, name = mathroman_groups_1_int2roman_2( , i = 0 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 3/13, countonly=15, sub_count=0, name = mathroman_groups_1_int2roman_3( , i = 12 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 4/13, countonly=16, sub_count=0, name = mathroman_groups_1_int2roman_4( , i = 17 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 5/13, countonly=17, sub_count=0, name = mathroman_groups_1_int2roman_5( , i = 18 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 6/13, countonly=18, sub_count=0, name = mathroman_groups_1_int2roman_6( , i = 19 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 7/13, countonly=19, sub_count=0, name = mathroman_groups_1_int2roman_7( , i = 111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 8/13, countonly=20, sub_count=0, name = mathroman_groups_1_int2roman_8( , i = 444 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 9/13, countonly=21, sub_count=0, name = mathroman_groups_1_int2roman_9( , i = 555 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 10/13, countonly=22, sub_count=0, name = mathroman_groups_1_int2roman_10( , i = 777 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 11/13, countonly=23, sub_count=0, name = mathroman_groups_1_int2roman_11( , i = 1111 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 12/13, countonly=24, sub_count=0, name = mathroman_groups_1_int2roman_12( , i = 4999 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 13/13, countonly=25, sub_count=0, name = mathroman_groups_1_int2roman_13( , i = 5000 ), , testcode = nil , argserrs = mathroman_null_value_err-0
      • TestsCases , recursive level = 1 n/N = 8/32 , group = mathroman_groups_14
    • n/N = 1/32, countonly=32, sub_count=0, name = mathroman_groups_14_roman2int_1( , rm = -X ), , testcode = nil , argserrs =
    • n/N = 2/32, countonly=33, sub_count=0, name = mathroman_groups_14_roman2int_2( , rm = 0 ), , testcode = nil , argserrs =
    • n/N = 3/32, countonly=34, sub_count=0, name = mathroman_groups_14_roman2int_3( , rm = ), , testcode = nil , argserrs =
    • n/N = 4/32, countonly=35, sub_count=0, name = mathroman_groups_14_roman2int_4( , rm = MCXI ), , testcode = nil , argserrs =
    • n/N = 5/32, countonly=36, sub_count=0, name = mathroman_groups_14_roman2int_5( , rm = XIJ ), , testcode = nil , argserrs =
    • n/N = 6/32, countonly=37, sub_count=0, name = mathroman_groups_14_roman2int_6( , rm = XJI ), , testcode = nil , argserrs =
    • n/N = 7/32, countonly=38, sub_count=0, name = mathroman_groups_14_roman2int_7( , rm = XIA ), , testcode = nil , argserrs =
    • n/N = 8/32, countonly=39, sub_count=0, name = mathroman_groups_14_roman2int_8( , rm = VLD ), , testcode = nil , argserrs =
    • n/N = 9/32, countonly=40, sub_count=0, name = mathroman_groups_14_roman2int_9( , rm = IXC ), , testcode = nil , argserrs =
    • n/N = 10/32, countonly=41, sub_count=0, name = mathroman_groups_14_roman2int_10( , rm = MMMMCMXCIX ), , testcode = nil , argserrs =
    • n/N = 11/32, countonly=42, sub_count=0, name = mathroman_groups_14_roman2int_11( , rm = MMMMM ), , testcode = nil , argserrs =
    • n/N = 12/32, countonly=43, sub_count=0, name = mathroman_groups_14_roman2int_12( , rm = MMMMMYJXC ), , testcode = nil , argserrs =
      • TestsCases , recursive level = 2 n/N = 8/8 , group = mathroman_groups_14_roman_group_13
    • n/N = 1/8, countonly=8, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_1( , i = 1 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 2/8, countonly=9, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_2( , i = 3 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 3/8, countonly=10, sub_count=0, name = mathroman_groups_14_roman_group_13_int2roman_3( , i = 6 ), , testcode = nil , argserrs = mathroman_null_value_err-0
    • n/N = 4/8, countonly=11, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_4( , rm = IV ), , testcode = nil , argserrs =
    • n/N = 5/8, countonly=12, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_5( , rm = V ), , testcode = nil , argserrs =
    • n/N = 6/8, countonly=13, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_6( , rm = III ), , testcode = nil , argserrs =
    • n/N = 7/8, countonly=14, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_7( , rm = VI ), , testcode = nil , argserrs =
    • n/N = 8/8, countonly=15, sub_count=0, name = mathroman_groups_14_roman_group_13_roman2int_8( , rm = I ), , testcode = nil , argserrs =
      • TestsCases , recursive level = 1 n/N = 4/4 , group = mathroman_tests_recursive_9
    • n/N = 1/4, countonly=4, sub_count=0, name = mathroman_tests_recursive_9_roman2int_1( , rm = XIJ ), , testcode = nil , argserrs =
    • n/N = 3/4, countonly=6, sub_count=0, name = mathroman_tests_recursive_9_roman2int_3( , rm = MCXI ), , testcode = nil , argserrs =

    tools.maini18n_languages_list[edit]

    tools.maini18n_languages_list()
    
    Returns the list of available languages.
    Example: "This module can translate 171 texts in 3 languages: English(en=English), español(es=Spanish), français(fr=French),".

    tools.luatablecount[edit]

    local res, tot_vars, tot_func, tot_tabs = tools.luatablecount(tab, tabname)
    
    tab is a luatable or a name of table in tools library like tools.args_known
    tabname is a name of the tab table.
    res is a string like "The table mathroman.i18n counts 30 texts, 0 functions, 3 sub-tables."
    In whole the table, the number of string is tot_vars, of functions is tot_func, of sub-tables is tot_tabs,

    tools.form_i18n_counts[edit]

    res = tools.form_i18n_counts(centre.maini18n, "maini18n = %1 texts translated in %2 languages.")
    
    Then res is a string like "maini18n = 157 sentences translated in 48 languages."

    mathroman library[edit]

    It converts decimal to roman numbers or reverse. It produces errors messages to explicite them. It have none interface(frame).

    mathroman.int2roman[edit]

    	mathroman.int2roman(int)
    
    Returns the roman number first, then eventual text of errors.
    Record also these errors in tools.errors_list.

    mathroman.roman2int[edit]

    	mathroman.roman2int(roman)
    
    Returns the decimal integer first, then eventual text of errors.
    Record also these errors in tools.errors_list.

    mathroman.tests_cases[edit]

    This is a first step to work on tests_cases. See also tools.str_test_case
    	mathroman.roman2int(roman)
    
    Returns the decimal integer first, then eventual text of errors.
    Record also these errors in tools.errors_list.
    --	Tests : class ClassNameTest extends Scribunto_LuaEngineTestBase
    --	protected static $moduleName = 'ClassNameTest';
    mathroman.tests_cases = { -- Autotest cases to validate the mathroman library at mediawiki level.
    	-- Each test_case defines a name, a function, an input, an output. See also tools.str_test_case.
    	{ name = 'mathroman.int2roman (1)', func = mathroman.int2roman, args = { 1 }, expect = { "I" } },
    	{ name = 'mathroman.int2roman (2)', func = mathroman.int2roman, args = { 2 }, expect = { "II" } },
    	{ name = 'mathroman.int2roman (3)', func = mathroman.int2roman, args = { 3 }, expect = { "III" } },
    	--
    	{ name = 'mathroman.roman2int (1)', func = mathroman.roman2int, args = { "I" }, expect = { 1 } },
    	{ name = 'mathroman.roman2int (2)', func = mathroman.roman2int, args = { "II" }, expect = { 2 } },
    	{ name = 'mathroman.roman2int (3)', func = mathroman.roman2int, args = { "III" }, expect = { 6 } },
    }
    
    Where to find documents or examples?
    Rical: I have search in phab, gerrit, mediawiki without success.
    For tests cases search "ClassNameTest" or "LuaEngineTestBase" or "LuaEngineTestBase::testLua" in class Lua reference manual .
    I found only my own code in 2013 in Module:Unitest_Scribunto
    But I don't know if it is efficient. How to submit a library to mediawiki check in gerrit?
    See also phab:T48635 Scribunto_LuaLibraryBase registerInterface() produces internal error on Windows platform

    See also[edit]