Module:ControlArgs

From Wikipedia

This module manage arguments for any module, which allows :

  • Assist the user settings, and even the developper of the module.
  • Read and display settings and messages in several languages.
  • options = " : docdata docmin docdef docmax docligne docavant docapres docnotice " -- for documentation
  • options = " erron noerr nobox nocat " -- without normal result
  • options = " debug notrack trackon testable en es fr " -- for debug or enforce language

normal sans args[edit]

{{#invoke:ControlArgs | normal | c = : }}

John Smith
L'auteur nil nil est mort en 1789 et son image est nil.
, initiale = S , firstname = nil , lastname = nil , title = John Smith , region = nil , rights = nil , language = nil

normal avec arguments[edit]

{{#invoke:ControlArgs | normal | c = : docdata docavant docdef | initiale= F | nom=Alain Fournier | description=Henri Alban Fournier (1886-1914), écrivain français, auteur notamment du roman Le Grand Meaulnes }}

John Smith
L'auteur nil nil est mort en 1789 et son image est nil.
, initiale = F , firstname = nil , lastname = nil , title = John Smith , region = nil , rights = nil , language = nil

langtest[edit]

{{#invoke:ControlArgs | langtest | c = : docdata docavant docdef }}


.

  • Tests in a few languages. Tests en quelques langues. Pruebas en unos pocos idiomas.  :

.

Test in english , user_lang = en , wiki_lang = fr

This documentation must be removed before recording. Remove all modes to return to normal mode.
.
Informations from: Wikidata, template or module, other, message, error.

{{ControlArgs | firstname = Arnaud
| country = France
| initiale = S
| firstname2 = Arnaud
| title = John Smith
| image = Carjat Arthur Rimbaud 1872 n2.jpg
| rights = 33
| label = John Smith
| language = french,italian,chinese
| deathyear = MDCCCJL
| region = Iowa
}}

  • User support about parameters:
    Internal Error: Module missing i18n translation entityid
    Abnormal value of the argument region = ailleurs among: (autre,chine,inde,siècle)
    Error: the value of the argument firstname is already defined. Choose only one argument and value.
    Error: the value of the argument lastname is already defined. Choose only one argument and value.
    Error: Too many unnamed arguments ( 2 ).
    Error: Too many unnamed arguments ( 3 ).
    Error: parameter region is unknown in this template. Check the name or flag this gap.
    Error: the known argument région is it the one you need ?
    Error: parameter language is unknown in this template. Check the name or flag this gap.
    Error: the known argument langue is it the one you need ?
  • Catégories : Module missing i18n translation Module with usage error Speaking french Speaking italian Speaking chinese Module with error
John Smith
L'auteur Arnaud nil est mort en MDCCCJL et son image est Carjat Arthur Rimbaud 1872 n2.jpg.
, initiale = S n= , firstname = Arnaud n= ac , lastname = nil n= ac , title = John Smith n=i=0 , region = Iowa n= a , rights = 33 n= am , language = french,italian,chinese n= ac

.

Prueba en español , user_lang = es , wiki_lang = fr

Esta documentación debe ser removido antes de grabar. Retire todos los modos para volver al modo normal.
.
Informacións de: Wikidata, modelo o módulo, otros, mensaje, error.

{{ControlArgs | apellido = Arnaud
| country = France
| inicial = S
| firstname2 = Arnaud
| titulo = John Smith
| imagen = Carjat Arthur Rimbaud 1872 n2.jpg
| rights = 33
| label = John Smith
| lengua = french,italian,chinese
| año de la muerte = MDCCCJL
| region = Iowa
}}

  • Asistencia en los parámetros del modelo en:
    err_module_miss_i18n
    Valor anormal del argumento region = ailleurs a partir de: (autre,chine,inde,siècle)
    Error: el valor del argumento firstname ya se ha definido. Elige uno sólo argumento y valor.
    Error: el valor del argumento lastname ya se ha definido. Elige uno sólo argumento y valor.
    Error: Demasiados argumentos sin nombre ( 2 ).
    Error: Demasiados argumentos sin nombre ( 3 ).
    Error: El parámetro region es desconocido en este modelo. Compruebe el nombre o marca esta brecha.
    Error: la région argumento conocido es el que necesita?
    Error: El parámetro language es desconocido en este modelo. Compruebe el nombre o marca esta brecha.
    Error: la langue argumento conocido es el que necesita?
  • Catégories : Módulo faltante traducción i18n Módulo con error del uso Habla french Habla italian Habla chinese Módulo con error
John Smith
L'auteur Arnaud nil est mort en MDCCCJL et son image est Carjat Arthur Rimbaud 1872 n2.jpg.
, initiale = S n= , firstname = Arnaud n= ac , lastname = nil n= ac , title = John Smith n=i=0 , region = Iowa n= a , rights = 33 n= am , language = french,italian,chinese n= ac

.

Test en français , user_lang = fr , wiki_lang = en

Cette documentation doit être supprimée avant d'enregistrer. Supprimez tous les modes pour revenir en mode normal.
.
Informations de : Wikidata, modèle ou module, autres, message, erreur.

{{ControlArgs | prénom = Arnaud
| pays = France
| initiale = S
| firstname2 = Arnaud
| titre = John Smith
| image = Carjat Arthur Rimbaud 1872 n2.jpg
| droits = 33
| label = John Smith
| langue = french,italian,chinese
| anneeDeces = MDCCCJL
| région = Iowa
}}

  • Assistance sur les paramètres de ce modèle :
    Erreur interne : manque de traduction pour entityid
    Valeur anormale de l'argument rights = 33 parmi : (70,50,mpf,none)
    Valeur anormale de l'argument region = Iowa parmi : (other,china,india,century)
    Erreur : La valeur de l'argument firstname est déjà définie. Choisir un seul argument et une seule valeur.
    Erreur : Trop de paramètres non nommés ( 2 ).
    Erreur : Le paramètre name est inconnu dans ce modèle. Vérifier ce nom ou signaler ce manque.
    Erreur : Le paramètre langue est inconnu dans ce modèle. Vérifier ce nom ou signaler ce manque.
    Erreur: L'argument connu language est-il celui que vous voulez ?
  • Catégories : Module manquant de traduction i18n Module avec erreur d'utilisation Parle french Parle italian Parle chinese Module avec erreur
John Smith
L'auteur Arnaud nil est mort en MDCCCJL et son image est Carjat Arthur Rimbaud 1872 n2.jpg.
, initiale = S n= , firstname = Arnaud n= ac , lastname = nil n= , title = John Smith n=i=0 , region = Iowa n= a , rights = 33 n= a , language = french,italian,chinese n= ac

tests[edit]

{{#invoke:ControlArgs | tests | c = : docdata docavant docdef }}


ControlArgs:tests:en

This documentation must be removed before recording. Remove all modes to return to normal mode.
.
Informations from: Wikidata, template or module, other, message, error.

{{Wikidata | country = France | deathyear = 1789 | label = John Smith}}

{{ControlArgs | country = France
| c = : docdata docavant docdef
| label = John Smith
| title = John Smith
| region = india
| deathyear = 1789
| initiale = S
}}

  • User support about parameters:
    Internal Error: Module missing i18n translation entityid
    Error: parameter région is unknown in this template. Check the name or flag this gap.
    Error: the known argument region is it the one you need ?
    Error: parameter nom is unknown in this template. Check the name or flag this gap.
    Error: parameter genre is unknown in this template. Check the name or flag this gap.
    Error: parameter name is unknown in this template. Check the name or flag this gap.
    Error: parameter langue is unknown in this template. Check the name or flag this gap.
    Error: the known argument language is it the one you need ?
    Error: parameter description is unknown in this template. Check the name or flag this gap.
    Error: parameter occupation is unknown in this template. Check the name or flag this gap.
  • Catégories : Module missing i18n translation Module with usage error Module with error
John Smith
L'auteur nil nil est mort en 1789 et son image est nil.
, initiale = S n= i , firstname = nil n= , lastname = nil n= , title = John Smith n= ii=2 , region = india n= am , rights = nil n= , language = nil n=

Category:Module missing i18n translationCategory:Module with usage errorCategory:Module with error

.

ControlArgs:tests:en


--[[ ControlArgs

-- Ce module ControlArgs permet d'adapter n'importe quel autre à un usage international avec tables I18N pour les noms d'arguments, le wikitexte, les catégories et les messages.
-- This module can adapt any other module for international use with I18N tables for argument names, wikitext, categories and errors.
-- see https://fr.wikisource.org/wiki/Module:ControlArgs
-- which adapts https://fr.wikisource.org/wiki/Module:Auteur

-- relire ControlArgs/Author : module code in english

-- A faire : Module code must be in english, documentation in the wiki language.

-- A faire : bug : get user language to help administrators to support wikis in other languages, by translated error messages.

-- A faire ? comment eviter qu'un argument de wikidata perde sans raison son origine ( src = "wd" ) ?
-- masquer les couleurs en attendant

-- A faire ? wikidata properties
-- A faire : wikidata un champ "date d'une oeuvre" ? voir date of publication (P577)
-- date of publication (P577) date when this work was published
-- language : native language (P103) language that a person learned natively
-- original language (P364) language in which a work was originally created
-- A faire : wikidata un champ "type de droit d'auteur" ? il y a P275, pour logiciels. quelques œuvres l'utilisent en marquant "domaine public" (ex: Q15677329), mais l'appliquer aux différentes déclinaisons de PD à la Commons n'a pas l'air habituel. Surtout que cette notion n'est pas absolue, mais dépend des pays. Peut-être en utilisant des qualificateurs ? --LBE (d) 1 juin 2014 à 16:55 (UTC)

-- A faire ? mots proches, tester des groupes d'erreurs de noms d'arguments pour des groupes d'arguments justes. near_word_search_diff_coef

-- A faire ? intégrer MathRoman ou séparer MathRoman+Epoque dans un nouveau module ?

-- A faire ? en l'absence de description, en composer une selon les catégories et infos de wikidata ?

-- a faire ? dans gener_doc, trier les arguments dans l'ordre alphabetique de la langue du wiki.

-- a faire ? suite a debat dans fr:wikipedia, comment choisir d'utiliser ou non une info de wikidata
-- par "-" pour « donnée dans l'article sinon rien » ou "+" pour « utiliser la valeur WD »
--		https://fr.wikipedia.org/wiki/Discussion_Projet:Infobox/Lua#Priorit.C3.A9_des_sources_de_donn.C3.A9es
--		Discussion_Projet:Infobox/Lua#Priorité des sources de données
-- The URI object has the following fields, some or all of which may be nil:
-- user: String user, query: A table, as from mw.uri.parseQueryString

-- relire ControlArgs/Auteur : module code in english

-- Fait : Lister i18n au format i18n.

-- Fait : liens wp + wk + commons + "Données structurées" -> lien vers wikibase OK

-- Fait : Si generDocBox est hors de Module ou Modèle alors : erreur et categorie "erreur d'utilisation"

-- Fait : display category without the word "Category".

-- Fait : 66539 - asked - Keep getEntity in cache for all modules and wikidata-templates in a page 
-- getEntityObject est très long a executer, 2 à 2.5 seconde, alors que cette entité a probablement déjà été liée pour les liens interwikis ou par interprojet. Peut-on éviter cette double requete ?
-- Même question si d'autres modules appellent la même entité, mais j'ai l'impression que pour ça c'est déjà le cas d'après les temps que j'ai observés.

-- Fait : Bug 51660 - asked - Detect the edit state to adapt help messages to user errors.
-- A faire : And detect also the create mode to adapt default values.
-- La plupart des erreurs sont utiles pendant l'édition de la page, mais génantes ensuite.
-- En attendant le Bug 51660 , on peut le remplacer par l'option manuelle "doc", et l'enlever avant de valider la page.

-- doc : need="0" not necessary argument
-- need="1" necessary from argument
-- need="2" necessary from argument or module interaction

--]]

------------------------------------------------------------
-- Interactions between modules :
-- Interactions inter modulos :
-- Interactions entre modules :
------------------------------------------------------------

--	Module dependencies. Dependencias del módulo. Dépendances du module.
--	local CA = require "Module:ControlArgs"

-- This module require the template {{Boîte déroulante/début}} and {{Boîte déroulante/fin}}
-- local CA = require "Module:ControlArgs" dans les sous modules
local I18N = require("Module:ControlArgs/I18N")
local p = {}
local CA = p
p.module_name = "ControlArgs"
-- CA.nowyear = tonumber(os.date("%Y") ) -- local now_date = os.date("%Y-%m-%d %H:%M:%S")
-- CA.nowyear = tonumber(os.date("%Y-%m-%d") ) -- local now_date = os.date("%Y-%m-%d %H:%M:%S")
-- p.nowyear = nowyear

CA.constants = CA.constants or {}
-- Similar words search : diff on length
-- Cerrar de palabras puscadas: diff en longitud
-- Recherche de mots proches: diff sur longueur
CA.constants.near_word_search_diff_coef = 0.30
CA.constants.near_word_search_diff_const = 0.82

------------------------------------------------------------
-- Tables des traductions des paramètres et messages dans les langues : en, es, fr.
-- Tables of translations of settings and messages in the languages : en, es, fr.
-- Mesas traducciones parámetros y mensajes en los idiomas : en, es, fr.
--
-- i18n translations tables to extend and update in calling modules
------------------------------------------------------------

p.i18n = {} -- Table des langues connues du module
p.i18n_args = {} -- Table des arguments exemples

p.i18n.en = {
	-- ControlArgs main texts, errors and categories
	[1]							= "1",
	["1"]						= "1",
	mode						= "mode",
	c							= 'c',
	debug						= 'debug',
	options						= 'options',
	category					= 'Category',
	catspace					= 'catspace',
	date_months_names			= "January, February, March, April, May, June, July, August, September, October, November, December",
	
	cat_test_OK					= "Test category generation OK",
	cat_usage_error				= "Module with usage error",
--		cats = cats .. p.cat_add("cat_usage_error")
--		cats = cats .. p.cat_add("cat_internal_error")
	cat_internal_error			= "Module with internal error",
	err_error_list_header		= "User support about parameters:",
	err_unknown_argument		= "Error: Argument '''%1''' = '''%2''' is unknown in this template. Check the name or flag this gap.",
	err_nearest_argument		= "Error: Do you need the known argument '''%1''' ?",
	max_nearest_argument		= 3,
	max_nearest_argument_msg	= "Near arguments are proposed if differences in length and letters are '''%1''' or less.",
	err_value_re_defined		= "Error: The argument '''%1''' is already defined. Choose only one argument and value.",
	err_need_value				= "Error: This argument is required but absent : '''%1'''. Should define it.",
	err_none_value				= "Error: No argument has been defined.",
	err_too_unnamed_arguments	= "Error: This unnamed argument is too many: '''%1''' = '''%2'''.",
	err_internal_notice_wsid	= "Internal Error: Notify the developer that the internal argument '''%1''' is unknown in the records.",
	err_without_translation		= "Known argument, but not translated: '''%1'''.",
	err_without_translation_N	= "There are %1 arguments untranslated.",
	err_is_defined				= "The argument %1:'''%2''' is defined.",
	err_is_undefined			= "The argument %1:'''%2''' is not defined.",
	err_module_with_error		= "Module with error",
	err_wikidata_wikibase		= "Error: Wikibase is not available.",
	err_wikidata_getEntity		= "Error: getEntity Wikidata is not available.",
	err_wikidata_getElement		= "Error: Element Wikidata '''%1''' is not found.",
	err_wikidata_property		= "Error: Wikidata property '''%1''' is not found.",
	err_wikidata_error			= "Error Wikidata: '''%1''' ",
--	err_wikidata_cat			= "Error Wikidata",
	err_wikidata_cat			= "Module with internal error",  -- cat_internal_error
	structured_data_txt			= 'Structured datas.',
	table_listlimit_levelmaxi	= "Level limit levelmaxi = '''%1''' ",
	table_listlimit_max_n		= "Length limit max_n = '''%1''' ",
	err_module_miss_i18n_txt	= "Internal Error: The text '''%1''' lack of translation in '''%2''' language, and/or others.",
	err_module_miss_i18n_count	= "Internal Error: There are '''%1''' missings in '''%2''' translations.",
	err_module_miss_i18n		= "Internal Error: Module missing i18n translation '''%1''' ",
--	err_module_miss_i18n_cat	= "Module missing i18n translation",
	err_module_miss_i18n_cat	= "Module with internal error",  -- cat_internal_error
	err_module_miss_i18n_mini	= "Error: I18n table has only '''1%''' translations.",
	i18n_list_all_texts			= "This list show all the texts, but cannot replace the original declarations.",
--	err_no_args_known			= "Error: Module without known arguments table.",
--	err_no_args_source			= "Error: Module without source arguments table.",
	languages_nbr_and_list		= "\n* There are %1 tables of translations in these languages : %2 <br/>",
	err_no_wiki_translations	= "Error: Module without translated arguments table.",
	err_no_args_wikidata		= "Error: Module without wikidata arguments table.",
	err_lang_table				= "Error: The '''%1''' language or its table is incorrect.",
--	err_lang_table_cat			= "Module with erroneous language arguments",
	err_lang_table_cat			= "Module with internal error",  -- cat_internal_error
	err_lang_not_exist			= "Error: The language '''%1''' is not one of wikipedias.",
	err_lang_not_translated		= "Error: The language '''%1''' is not translated.",
	err_argv_args_src			= "Internal Error: in p.argv, arguments table is missing.",
	err_argv_args_name			= "Internal Error: in p.argv, abnormal argument '''%1'''.",
	err_argv_args_miss			= "Internal Error: in p.argv, missing argument '''%1'''.",
	err_generDoc1_paramName		= "Internal Error: in generDoc1, bad argument '''%1'''.",
	sources_of_datas			= "Informations from: /Wikidata, /template or module, /other, /message, /error",

	err_delete_docbox			= "This documentation must be removed before recording.\nRemove all modes to return to normal mode.",
	err_assist_user_param		= "User support for checking the settings:",
--	err_module_error			= "Module with error",
	err_module_with_error		= "Module with error",
	msg_auto_val_warning		= "Verify the automatic argument: %1 = '''%2'''.",
	msg_auto_val_unknown		= "Internal Error: Unknown automatic argument: %1 = '''%2'''.",
	--
	err_no_known_arguments		= "Internal Error: Module without known arguments table.",
--	cat_no_known_arguments		= "Module without known arguments table.",
	cat_no_known_arguments		= "Module with internal error",  -- cat_internal_error
	err_no_source_arguments		= "Internal Error: Module without source arguments table.",
--	cat_no_source_arguments		= "Module without source arguments table.",
	cat_no_source_arguments		= "Module with internal error",  -- cat_internal_error

	date_to_part_format			= " dd yyyy mmmm",
	date_to_part_call_err		= "Internal Error: Abnormal calling arguments in date '''%1'''.",
	date_to_part_call_cat		= "Module with internal error",
	date_to_part_err_not_found	= "Internal Error: No part found in date '''%1'''.",

	-- ControlArgs example : arguments names, errors and categories
	label						= 'label',
	sitelink					= 'sitelink',
	lastname					= 'name',
	firstname					= 'firstname',
	initiale					= 'initiale',
	title						= 'title',
	image						= 'image',
	birthyear					= 'birthyear',
	deathyear					= 'deathyear',
	cat_name_number				= "Year %1",
	debug						= "debug",
	language					= 'language',
	country						= 'country',
	genre_cat					= '%1',
	language_cat				= 'Speaking %1',
	occupation_cat				= '%1',

	-- arguments with verified multiple values
	region						= 'region',
	region_values				= 'other,china,india,century',
	rights						= 'rights',
	rights_values				= '70,50,mpf,none',
	args_values_err				= "Abnormal value of the argument '''%1 = %2''' among: (%3) ",
} -- p.i18n.en

p.i18n.es = {
	date_months_names			= "Enero, Febrero, Marzo, Abril, Mayo, Junio​​, Julio, Agosto, Septiembre, Octubre, Noviembre, Diciembre",
	
	cat_usage_error				= "Módulo con error del uso",
	cat_internal_error			= "Módulo con error interno",
	err_module_with_error		= "Módulo con error",
	err_too_unnamed_arguments	= "Error: Demasiado argumento sin nombre: '''%1''' = '''%2'''.",
	languages_nbr_and_list		= "\n* Hay %1 mesas de traducciones en estas idiomas: %2 <br/>",
	sources_of_datas			= "Informacións de: /Wikidata, /modelo o módulo, /otros, /mensaje, /error",
	err_delete_docbox			= "Esta documentación debe ser removido antes de grabar.\nRetire todos los modos para volver al modo normal.",
	structured_data_txt			= 'Datos&nbsp;estructurados.',
	msg_auto_val_warning		= "Verifique el argumento automático: %1 = '''%2'''.",
	msg_auto_val_unknown		= "Error interno: Argumento desconocido automático: %1 = '''%2'''.",
	err_unknown_argument		= "Error: Argumento '''%1''' = '''%2''' es unknown en esta templato. Check the name or flag this gap.",
	args_values_err				= "Valor anormal del argumento '''%1 = %2''' a partir de: (%3) ",
	genre_cat					= '%1',
	language_cat				= 'Habla %1',
	occupation_cat				= '%1',

	date_to_part_format			= " dd yyyy mmmm",
	date_to_part_call_err		= "Internal Error: Abnormal calling arguments in date '''%1'''.",
	date_to_part_call_cat		= "Module with internal error",
	date_to_part_err_not_found	= "Internal Error: No part found in date '''%1'''.",
	
	i18n_list_all_texts			= "Esta lista muestra todos los textos, pero no puede sustituir a las declaraciones originales.",
} -- p.i18n.es

p.i18n.fr = {
	-- Principaux textes, erreurs et catégories de ControlArgs
	[1]							= "1",
	["1"]						= "1",
	mode						= "mode",
	c							= 'c',
	debug						= 'debug',
	options						= 'options',
	category					= 'Catégorie',
	catspace					= 'catspace',
	date_months_names			= "Janvier, Février, Mars, Avril, Mai, Juin, Juillet, Août, Septembre, Octobre, Novembre, Décembre",
	cat_test_OK					= "Test de génération de catégorie OK",
	cat_usage_error				= "Module avec erreur d'utilisation",
	cat_internal_error			= "Module avec erreur interne",
	err_error_list_header		= "Assistance sur les paramètres de ce modèle :",
	err_unknown_argument		= "Erreur : Le paramètre '''%1''' = '''%2''' est inconnu dans ce modèle. A vérifier ou à signaler.",
	err_nearest_argument		= "Erreur : Voulez vous l'argument connu '''%1''' ?",
	max_nearest_argument		= 3,
	max_nearest_argument_msg	= "Des arguments proches sont proposés jusqu'à '''%1''' différences de lettres.",
	err_value_re_defined		= "Erreur : L'argument '''%1''' est déjà défini. Choisir un seul argument et une seule valeur.",
	err_need_value				= "Erreur : Vous devez définir cet argument nécessaire mais absent : '''%1'''.",
	err_none_value				= "Erreur : Aucun argument n'a été défini.",
	err_too_unnamed_arguments	= "Erreur : Ce paramètre non nommé est en trop : '''%1''' = '''%2'''.",
	err_internal_notice_wsid	= "Erreur interne : Signaler au développeur que l'argument interne '''%1''' est inconnu dans les notices.",
	err_without_translation		= "Argument connu, mais non traduit : '''%1'''.",
	err_without_translation_N	= "Il y a %1 arguments non traduits.",
	err_is_defined				= "L'argument %1:'''%2''' est défini.",
	err_is_undefined			= "L'argument %1:'''%2''' n'est pas défini.",
	err_module_with_error		= "Module avec erreur",
	err_wikidata_wikibase		= "Erreur : Wikibase n'est pas disponible.",
	err_wikidata_getEntity		= "Erreur : getEntity Wikidata n'est pas disponible.",
	err_wikidata_getElement		= "Erreur : L'élément ''' %1 ''' de Wikidata n'est pas trouvé.",
	err_wikidata_property		= "Erreur : La propriété '''%1''' de Wikidata n'est pas trouvé.",
	err_wikidata_error			= "Erreur Wikidata : '''%1''' ",
	err_wikidata_cat			= "Erreur Wikidata",
	structured_data_txt			= 'Données&nbsp;structurées.',
	table_listlimit_levelmaxi	= "Limite de niveau levelmaxi = '''%1''' ",
	table_listlimit_max_n		= "Limite de longueur max_n = '''%1''' ",
	err_module_miss_i18n_txt	= "Erreur interne : Le texte '''%1''' manque de traduction en langue '''%2''', et/ou d'autres.",
	err_module_miss_i18n_count	= "Erreur interne : Il y a '''%1''' manques parmi '''%2''' traductions.",
	err_module_miss_i18n		= "Erreur interne : manque de traduction pour '''%1''' ",
--	err_module_miss_i18n_cat	= "Module manquant de traduction i18n",
	err_module_miss_i18n_cat	= "Module avec erreur interne", -- cat_internal_error
	err_module_miss_i18n_mini	= "Erreur interne : La table i18n n'a que '''%1''' traductions.",
	i18n_list_all_texts			= "Cette liste montre tous les textes, mais ne peut remplacer les déclarations originales.",
--	err_no_args_known			= "Erreur interne : Module sans table d'arguments connus.",
--	err_no_args_source			= "Erreur interne : Module sans table d'arguments sources.",
	languages_nbr_and_list		= "\n* Il y a %1 tables de traductions dans ces langues : %2 <br/>",
	err_no_wiki_translations	= "Erreur interne : Module sans table d'arguments traduits.",
	err_no_args_wikidata		= "Erreur interne : Module sans table d'arguments wikidata.",
	err_lang_table				= "Erreur interne : La langue '''%1''' ou sa table est erronée.",
--	err_lang_table_cat			= "Module avec langue d'arguments erronée",
	err_lang_table_cat			= "Module avec erreur interne", -- cat_internal_error
	err_lang_not_exist			= "Erreur : La langue '''%1''' n'est pas une des langues des wikipedias.",
	err_lang_not_translated		= "Erreur : La langue '''%1''' n'est pas traduite.",
	err_argv_args_src			= "Erreur interne : en p.argv, table d'arguments absente.",
	err_argv_args_name			= "Erreur interne : en p.argv, argument anormal '''%1'''.",
	err_argv_args_miss			= "Erreur interne : en p.argv, argument absent '''%1'''.",
	err_generDoc1_paramName		= "Erreur interne : en generDoc1, mauvais argument '''%1'''.",
	sources_of_datas			= "Informations de : /Wikidata, /modèle ou module, /autres, /message, /erreur",

	err_delete_docbox			= "Cette documentation doit être supprimée avant d'enregistrer.\nSupprimez tous les modes pour revenir en mode normal.",
	err_assist_user_param		= "Support aux utilisateurs pour vérifier les paramètres :",
--	err_module_error			= "Module avec erreur.",
	msg_auto_val_warning		= "Vérifiez l'argument automatique : %1 = '''%2'''.",
	msg_auto_val_unknown		= "Erreur interne: Argument automatique inconnu : %1 = '''%2'''.",
	--
	err_no_known_arguments		= "Erreur interne : Module sans table d'arguments connus.",
--	cat_no_known_arguments		= "Module sans table d'arguments connus.",
	cat_no_known_arguments		= "Module avec erreur interne", -- cat_internal_error
	err_no_source_arguments		= "Erreur interne : Module sans table d'arguments sources.",
--	cat_no_source_arguments		= "Module sans table d'arguments sources.",
	cat_no_source_arguments		= "Module avec erreur interne", -- cat_internal_error

	date_to_part_format			= " dd yyyy mmmm",
	date_to_part_call_err		= "Internal Error: Abnormal calling arguments in date '''%1'''.",
	date_to_part_call_cat		= "Module with internal error",
	date_to_part_err_not_found	= "Internal Error: No part found in date '''%1'''.",

	-- Exemple ControlArgs : textes, erreurs et catégories
	label						= 'label',
	sitelink					= 'sitelink',
	lastname					= 'nom',
	firstname					= 'prénom',
	initiale					= 'initiale',
	title						= 'titre',
	image						= 'image',
	birthyear					= 'anneeNaissance',
	deathyear					= 'anneeDeces',
	rights						= 'droits',
	language					= 'langue',
	genre_cat					= '%1',
	language_cat				= 'Parle %1',
	occupation_cat				= '%1',
	cat_name_number				= "Année %1",
	debug						= "debug",
	country						= 'pays',

	-- Arguments à valeurs multiples vérifiées
	region						= 'région',
	region_values				= "autre,chine,inde,siècle",
	rights						= 'droits',
	rights_values				= '70,50,mpf,non',
	args_values_err				= "Valeur anormale de l'argument '''%1 = %2''' parmi : (%3) ",
} -- p.i18n.fr

------------------------------------------------------------
-- p.i18n tables end
------------------------------------------------------------

------------------------------------------------------------
-- Arguments table, to change in calling modules
------------------------------------------------------------

p.args_known_default = {

	-- Arguments in order without names, with their keyword for use as other arguments.
	-- Arguments dans l'ordre, non nommés, avec leur keyword pour traitement comme les autres arguments.

	[1] =			{need = 0, list = 1, syn = 1,
		keyword = "mode"},

	mode =			{typ = "prg", need = 0, list = 1,
		keyword = "mode"},

	-- Special arguments to modify the fonctions and outputs of this module.
	-- Arguments speciaux pour modifier le fonctionnement et les sorties de ce module.

	c =				{typ = "opt", need = 0, list = 1,
		keyword = "c"},

	options =		{typ = "opt", need = 0, list = 1,
		keyword = "options"},

	debug =			{typ = "opt", need = 0, list = 1,
		keyword = "debug"},

	-- All arguments have a keyword identical to the registration name, except synonyms.
	-- Tous les arguments ont un keyword identique au nom d'enregistrement, sauf les synonymes.

	label =			{typ = "dat", need = 0, list = 2,
		keyword = "label" , prop = "label"},

	country =		{typ = "dat", need = 0, list = 3,
		keyword = "country", prop = "27", },

	sitelink =		{typ = "dat", need = 0, list = 2,
		keyword = "sitelink" , prop = "sitelink"},

	entityid =		{typ = "dat", need = 2, list = 2,
		keyword = "entityid" , prop = "entityid"},

	lastname =		{typ = "dat", need = 0, list = 2,
		keyword = "lastname"},

	lastname2 =		{typ = "dat", need = 0, list = 2, syn = 1,
		keyword = "lastname"},

	firstname =		{typ = "dat", need = 0, list = 2,
		keyword = "firstname"},

	firstname2 =	{typ = "dat", need = 0, list = 2, syn = 1,
		keyword = "firstname"},

	initiale =		{typ = "dat", need = 2, list = 2,
		keyword = "initiale"},

	title =			{typ = "dat", need = 2, list = 2,
		keyword = "title"},

	image =			{typ = "dat", need = 0, list = 2,
		keyword = "image", prop = "18"},

	birthyear =		{typ = "dat", need = 0, list = 2,
		keyword = "birthyear", prop = "569", format = "year"},

	deathyear =		{typ = "dat", need = 0, list = 2,
		keyword = "deathyear", prop = "570", format = "year"},

	language =		{typ = "dat", need = 0, list = 3,
		keyword = "language"},

	category =		{typ = "ctr", need = 0, list = 3,
		keyword = "category"},

	-- arguments managed only by program, not read from template
	catspace =	{typ = "prg", need = 0, list = 9,
		keyword = "catspace"},

	region =		{typ = "dat", need = 0, list = 2,
		keyword = "region", arg_values = "region_values", keys_values = "other,china,india,century" },

	rights =		{typ = "dat", need = 0, list = 1, prop = "275",
		keyword = "rights", arg_values = "rights_values", keys_values = "70,none,50,mpf" },

} -- p.args_known_default

-- relire ControlArgs/Auteur : module code in english

------------------------------------------------------------
-- Main tables of arguments. Principales tablas de argumentos. Principales tables d'arguments.
------------------------------------------------------------

p.args_source_example = { "Hugo", "Victor", "arg3", c = ' docdef docview docsrc erron ', nom = 'Voltaire', nomm = 'Voltaire', anneenaissance = '1987', BNF = '123456789' }

CA.wiki_lang = "fr" -- mw.language.getContentLanguage().code -- language of usual wiki for args and categories
CA.wiki_translations = nil -- = p.i18n[p.wiki_lang] -- translations in the wiki language of identifiers, errors and messages
CA.user_lang = "en" -- user language for errors and messages
CA.user_translations = nil -- translations in the user language of identifiers, errors and messages
p.msgs_list = CA.user_translations -- = p.i18n[p.user_lang] -- translations in the user language of identifiers, errors and messages

p.args_known = nil -- Table of the definitions of all known arguments at module level.
p.args_wikidata = nil -- Table of present arguments values from wikidata
p.args_source = nil -- Table of source arguments from calling template, based on argument names in wiki language
p.args_unknown = nil -- unknown arguments are source arguments without known arguments.
p.args_import = nil -- Table of values of all imported arguments, based on international english keys
p.args_final = nil -- Table of values of arguments after interactions between them
p.max_nearest_argument = 3 -- Limit of differences of arguments proposed to the user
CA.args_wikidata_import = nil -- Table of the first complete import from wikidata
CA.args_wikidata_selected = nil -- Table of imported arguments from wikidata after any selection

p.categories_list = {} -- Table to collect all categories to generate in wikitext
p.catView = "" -- = ":" to document a category rather than truly categorize it
p.category_space = mw.site.namespaces.Category.name -- translated Category namespace
CA.trkView = false -- debug trak .trk of sources of arguments .src

------------------------------------------------------------
-- Miscelanous functions. Fonctions utilitaires.
------------------------------------------------------------

-- A faire ? to detect create mode : mw.title.getContent(): Returns the (unparsed) content of the page, or nil if there is no page. The page will be recorded as a transclusion.
-- mw.title.getCurrentTitle() Returns the title object for the current page.
function p.get_edit_state(t) -- iterator to use all elements of a table, one by one
	-- for noticeN in p.table_iterator(notices_properties) do
	-- modele : function list_iter (t)
	if type(t) ~= "table" then return {}, 0 ,0 end
	local i = 0
	local n = table.getn(t)
	return function ()
		i = i + 1
		n = table.getn(t)
		if t[i] ~= nil then return t[i], i ,n end
	end
end -- function p.get_edit_state(t)

function p.table_iterator(t) -- iterator to use all elements of a table, one by one
	-- for noticeN in p.table_iterator(notices_properties) do
	-- modele : function list_iter (t)
	if type(t) ~= "table" then return {}, 0 ,0 end
	local i = 0
	local n = table.getn(t)
	return function ()
		i = i + 1
		n = table.getn(t)
		if t[i] ~= nil then return t[i], i ,n end
	end
end -- function p.table_iterator(t)

function CA.get_namespaces()
	local res = ""
	--[[
	local localspace = mw.title.getCurrentTitle().namespace -- tit.namespace: The namespace number.
	local canonicalName = mw.site.namespaces[localspace].canonicalName
	local isContent = mw.title.getCurrentTitle().isContentPage -- tit.isContentPage: Whether this title is in a content namespace.
	res = res .. CA.ta("localspace", localspace) .. CA.ta("canonicalName", canonicalName) .. CA.ta("isContent", isContent)
	local ns_tab = {}
	--]]
	local ns = ""
	for ins = 0, 2000 do
	--	if mw.site.contentNamespaces[ins] then
		if mw.site.namespaces[ins] then
			ns = mw.site.namespaces[ins].canonicalName
			res = res .. CA.ta(ns, ins)
		end
	end
	return res
end -- function CA.get_namespaces()

function p.search_namespace(res)
	local res = res or "\n* '''search_namespace''' :"
	local mwtitle = mw.title.getCurrentTitle()
	res = res .. p.ta("mwtitle", mwtitle)
	local baseText = mwtitle.baseText -- namespace for the page
	res = res .. p.ta("baseText", baseText)
	local nsText = mwtitle.nsText
	res = res .. p.ta("nsText", nsText)
	local url = tostring(mwtitle:canonicalUrl( ))
	res = res .. p.ta("url", url)
	--
	res = res .. "\n* Module namespace : "
	local ns = mw.site.namespaces
	if ns and ns[828] then
		res = res .. p.ta("id828", ns[828].id)
		res = res .. p.ta("canonicalName828", ns[828].canonicalName)
		res = res .. p.ta("name828", ns[828].name)
		res = res .. p.ta("displayName828", ns[828].displayName)
	end
	res = res .. "\n* All namespaces : "
-- .. CA.get_namespaces()
	local ns = ""
	for ins = 0, 2000 do
	--	if mw.site.contentNamespaces[ins] then
		if mw.site.namespaces[ins] then
			ns = mw.site.namespaces[ins].canonicalName
			res = res .. CA.ta(ns, ins)
		end
	end
	return res
end -- function p.search_namespace()

-- Some usual fonctional styles for this module and those using it.
-- Quelques styles fonctionnels banals dans ce module et ses modules appelants.
function p.error_color(t)
	return '<span style="color:red;" >' .. tostring(t) .. '</span>'
end

function p.message_color(t)
	return '<span style="color:blue;" >' .. tostring(t) .. '</span>'
end

function p.wikidata_color(t)
	return '<span style="color:green;" >' .. tostring(t) .. '</span>'
end

function p.invoke_color(t)
	return '<span style="color:#804020;" >' .. tostring(t) .. '</span>'
end

function p.other_color(t)
	return '<span style="color:black;" >' .. tostring(t) .. '</span>'
end

function p.isDef(x) -- x is defined or no. x est défini ou non
	return (type(x) == "string") and (x ~= "") and (x ~= " ") and (x ~= "nil")
end

function p.ta(txt, val, sep) -- Met en forme un argument et sa valeur dans une documentation
	if not val then val = "nil" end
	if not sep then sep = "=" end
	return " , " .. tostring(txt) .. " " .. sep .. " ''' " .. tostring(val) .. " ''' "
end

function p.tam(txt, val, sep) -- Met en forme un argument, ou le masque s'il est nul.
	if not val then return "" end
	return p.ta(txt, val, sep)
end

function p.string_vars(translations, ref, v1, v2, v3, v4, v5)
	-- replace %1 to %5 by v1 to v5 in the user translation of ref, else in ref
	ref = tostring(ref)
	local wt = " stv "
	if translations and translations[ref] then
		wt = tostring(translations[ref]) -- Utiliser ref comme reference du texte
	else
		wt = tostring(ref) -- Sinon utiliser ref comme le texte lui-même.
	end
	v1 = v1 or " "
	v2 = v2 or " "
	v3 = v3 or " "
	v4 = v4 or " "
	v5 = v5 or " "
	if v1 then wt = string.gsub(wt, "%%1", tostring(v1) ) end
	if v2 then wt = string.gsub(wt, "%%2", tostring(v2) ) end
	if v3 then wt = string.gsub(wt, "%%3", tostring(v3) ) end
	if v4 then wt = string.gsub(wt, "%%4", tostring(v4) ) end
	if v5 then wt = string.gsub(wt, "%%5", tostring(v5) ) end
	return tostring(wt)
end -- function p.string_vars(translations, ref, v1, v2, v3, v4, v5)

function p.str_vars(ref, v1, v2, v3, v4, v5)
	-- replace %1 to %5 by v1 to v5 in the user translation of ref, else in ref
	return p.string_vars(CA.user_translations, ref, v1, v2, v3, v4, v5)
end -- function p.str_vars(ref, v1, v2, v3, v4, v5)

function CA.wiki_vars(ref, v1, v2, v3, v4, v5)
	-- replace %1 to %5 by v1 to v5 in the wiki translation of ref, else in ref
	return p.string_vars(CA.wiki_translations, ref, v1, v2, v3, v4, v5)
end -- function CA.wiki_vars(ref, v1, v2, v3, v4, v5)

function p.str_STR_N(wt_ref, v1, v2, v3)
	-- replace STR_1 to STR_3 by v1 to v3 in the translation of wt_ref, else in wt_ref
	wt_ref = tostring(wt_ref)
	local wt = ""
	if CA.wiki_translations and CA.wiki_translations[wt_ref]
		then wt = tostring(CA.wiki_translations[wt_ref]) -- Utiliser wt_ref comme la reference de texte traduit.
		else wt = tostring(wt_ref) end -- Sinon utiliser wt_ref comme le texte lui-même.
	if v1 then wt = string.gsub(wt, "STR_1", tostring(v1) ) end -- REF_1
	if v2 then wt = string.gsub(wt, "STR_2", tostring(v2) ) end
	if v3 then wt = string.gsub(wt, "STR_3", tostring(v3) ) end
	return wt
end -- function p.str_STR_N(wt_ref, v1, v2, v3)

function p.dropdown_box(if_view, title, contenu, alignT)
	-- Insérer le "contenu" dans la boite déroulante "title" et l'aligner par défaut à gauche(left), sinon à droite(right) ou au centre(center).
	if (if_view == false) or (if_view == 0) or (not if_view) then return "" end
	if not contenu then contenu = " Boîte vide " end
	if not title then title = " Boîte déroulante " end
	if not alignT then alignT = "left" end
	local frame = mw.getCurrentFrame()
	local txt = "{{Boîte déroulante/début|titre=" .. title .. "|alignT=" .. alignT .. "}}" .. contenu .. "{{Boîte déroulante/fin}}"
	local res = frame:preprocess( txt )
	return res
--	frame:expandTemplate{ title = title, args = table }
end -- function p.dropdown_box(if_view, title, contenu, alignT)

------------------------------------------------------------
-- Document the tables and their structures. List a table content, with formating.
-- Documentar las tablas y sus estructuras. Lista de un contenido de la tabla, con el formateo.
-- Documenter les tables et leurs structures. Lister un contenu de la table, avec le formatage.
------------------------------------------------------------

-- Dump and format the content of a table and its sub-tables ; with limits in length, deep and exceptions.
-- Listar y formatar le contento de una tabla y su sub-tablas.
-- Lister et formater le contenu d'une table et ses sous-tables ; avec des limites en longueur, profondeur et exceptions.
-- For each (sub)table, list : in first vars, then functions, then sub-tables list, then sub-tables contents

function p.testable_recursive(tbl, uppername, name, level_i, levelmaxi, max_n, exclude1, exclude2, exclude3)
	if type(name) ~= "string" then name = "table" end
	local res, newname, part, shift = "", "", "", ""
	local sep, N = ", ", 0
	local isempty = true
	local levelname = uppername .. "." .. name
	local tot_vars, tot_func, tot_tabs = 0, 0, 0
	local nbr_vars, lst_vars = 0, ""
	local nbr_func, lst_func = 0, ""
	local nbr_tabs, lst_tabs = 0, ""
	local max, lst_subtabs = 0, ""
	local st, vr, fn, tb = "", 0, 0, 0
	local tobreak = nil
	-- limit the number of the level of sub-tables
	level_i = tonumber(level_i)
	if type(level_i) ~= "number" then level_i = 1 end
	levelmaxi = tonumber(levelmaxi)
	if type(levelmaxi) ~= "number" then levelmaxi = 99 end
	if level_i > levelmaxi then
		return p.message_color( " display list levelmaxi=" .. tostring(levelmaxi) ), tot_vars, tot_func, tot_tabs
	end
	max_n = tonumber(max_n) or 999
	shift = string.rep("*", level_i)
	--
	-- Do not list if exclude1, exclude2 or exclude3 are in the table name.
	if type(exclude1) == "string" and exclude1 ~= "" then
		if string.find(name, exclude1) ~= nil then
			return "", tot_vars, tot_func, tot_tabs
		end
	end
	if type(exclude2) == "string" and exclude2 ~= "" then
		if string.find(name, exclude2) ~= nil then
			return "", tot_vars, tot_func, tot_tabs
		end
	end
	if type(exclude3) == "string" and exclude3 ~= "" then
		if string.find(name, exclude3) ~= nil then
			return "", tot_vars, tot_func, tot_tabs
		end
	end
	-- display table error
	if type(tbl) ~= "table" then
		return '<br/>Table "' .. tostring(name) .. '" is invalid.<br/>', tot_vars, tot_func, tot_tabs
	end
	--
	-- List and count vars, functions and sub tables
	-- All named elements, including [1] and ["1"].
	-- Tous les élements, y compris [1] et ["1"].
	for k, v in pairs(tbl) do
		k = tostring(k)
		if type(v) == "table" then
			lst_tabs = lst_tabs .. k .. sep
			nbr_tabs = nbr_tabs + 1
			isempty = false
			newname = tostring(k)
			max = max + 1
			-- List recursively (or no) each sub-table
			if level_i < levelmaxi then
				st, vr, fn, tb = p.testable_recursive(v, levelname, newname, level_i+1, levelmaxi, max_n, exclude1, exclude2, exclude3)
				lst_subtabs = lst_subtabs .. st
				tot_vars = tot_vars + vr
				tot_func = tot_func + fn
				tot_tabs = tot_tabs + tb + 1
			end
			if level_i >= levelmaxi then
				local table_listlimit_levelmaxi = p.str_vars("table_listlimit_levelmaxi", levelmaxi)
				res = res .. " " .. p.message_color( table_listlimit_levelmaxi )
				break
			end
			local sep = ""
			if max == max_n then
				local table_listlimit_max_n = p.str_vars("table_listlimit_max_n", max_n)
				res = res .. "\n" .. shift .. " Table '''" .. levelname .. "''' " .. p.message_color(table_listlimit_max_n)
				break
			end
--			end
		elseif type(v) == "function" then
			lst_func = lst_func .. k .. sep
			nbr_func = nbr_func + 1
			tot_func = tot_func + 1
			isempty = false
		else -- type(v) == other
			lst_vars = lst_vars .. type(v) .. " - " .. tostring(k) .. " =''' " .. tostring(v) .. "''' " .. sep
			nbr_vars = nbr_vars + 1
			tot_vars = tot_vars + 1
			isempty = false
		end
	end
	res = res .. "\n" .. shift .. " Table '''" .. levelname .. "''', " .. tostring(nbr_vars) .. " vars: " .. lst_vars
	res = res .. "\n" .. shift .. " Table '''" .. levelname .. "''', " .. tostring(nbr_func) .. " functions: " .. lst_func
	res = res .. "\n" .. shift .. " Table '''" .. levelname .. "''', " .. tostring(nbr_tabs) .. " tables: " .. lst_tabs .. lst_subtabs
	return res, tot_vars, tot_func, tot_tabs
end -- function p.testable_recursive(tbl, uppername, name, level_i, levelmaxi, max_n, exclude1, exclude2, exclude3)

-- Auto test of limits of the table list.
-- Auto test des limites de liste de table.
p.tablim = { "one", "two", max1 = "MAX1", max2 = "MAX2", max3 = "MAX3"}
p.tablim.life = { animal = "dog", vegetal = "carot"}
p.tablim.life.animals = { "turtle"}
p.tablim.comfort = { "tv", mobile = "car"}
p.tablim.house = { "kitcheen", "bedroom"}
p.tablim.house.garden = { flower = "rose", nature = "river"}

function p.testable_lister(table, tablename, opt)
	local res = "\n\n* Content of the '''" .. tostring(tablename) .. "''' table, begin:"
	-- test : check mw content
	if not opt then opt = { levelmaxi = 99 } end
	local levelmaxi = opt.levelmaxi or 99
	local max_n = opt.max_n or 9999
	local exclude1 = opt.exclude1 or ""
	local exclude2 = opt.exclude2 or ""
	local exclude3 = opt.exclude3 or ""
	local tot_vars, tot_func, tot_tabs = 0, 0, 0
	-- limit the number of the level of sub-tables
	level_i = tonumber(level_i)
	if type(level_i) ~= "number" then level_i = 1 end
	levelmaxi = tonumber(levelmaxi)
	if type(levelmaxi) ~= "number" then levelmaxi = 99 end
	if level_i > levelmaxi then
		return "", tot_vars, tot_func, tot_tabs
	end
	res = res .. " ( " .. CA.ta("levelmaxi", levelmaxi) .. CA.ta("max_n", max_n) .. CA.ta("exclude1", exclude1) .. CA.ta("exclude2", exclude2) .. CA.ta("exclude3", exclude3) .. " ) "
	local st, vr, fn, tb = p.testable_recursive(table, "", tablename, 1, levelmaxi, max_n, exclude1, exclude2, exclude3)
	res = res .. st
	tot_vars = tot_vars + vr
	tot_func = tot_func + fn
	tot_tabs = tot_tabs + tb
	res = res .. "\n\n* Content of the '''" .. tostring(tablename) .. "''' table, end: "
	res = res .. p.str_vars(" %1 variables, %2 functions, %3 sub-tables.\n", vr, fn, tb)
	return res, tot_vars, tot_func, tot_tabs
end -- function p.testable_lister(table, tablename, opt)

-- relire ControlArgs/Auteur : module code in english

-- Remplacer ou ajouter tous les champs de la table add à la table de base, sur un seul niveau.
function p.table_mixer(base, add)
	local v2, nn, ni = 0, 0, 0
	local tb = {}
	 -- cumuler les elements
	if type(base) == "table" and type(add) == "table" then
		for i, val in ipairs(base) do
			v2 = mw.clone( val )
			tb[i] = v2
		end
		for i, val in ipairs(add) do
			v2 = mw.clone( val )
			tb[i] = v2
		end
		for key, val in pairs(base) do
			v2 = mw.clone( val )
			tb[key] = v2
		end
		for key, val in pairs(add) do
			v2 = mw.clone( val )
			tb[key] = v2
		end
	else
		tb = base
	end
	-- compter les elements
	if type(tb) == "table" then
		for i, val in ipairs(tb) do
			ni = ni + 1
		end
		for key, val in pairs(tb) do
			nn = nn + 1
		end
	end
	return tb, ni, nn
end -- function p.table_mixer(base, add)

------------------------------------------------------------
-- Manage translations of arguments and messages
-- Gestione traducciones de argumentos y mensajes
-- Gérer les traductions des arguments et messages
------------------------------------------------------------

function p.trans(key) -- give the translation of indentified texts, or arguments indentifier, or errors messages
	local t = CA.wiki_translations[key]
	if t == nil then t="" end
	return t
end

function p.get_IETF_fr()
	-- Chargement de la base de donnée des langues avec gestion d'erreur.
	-- voir : https://fr.wikipedia.org/wiki/Module:Langue
	local dataLangue
	local success, resultat = pcall (mw.loadData, 'Module:Langue/Data' )
	if success then
		dataLangue = resultat
	else
		-- Base de donnée à minima en cas de bug sur le Module:Langue/Data
		dataLangue = {
			en = { code = 'en', nom = 'anglais' },
			fr = { code = 'fr', nom = 'français' },
			de = { code = 'de', nom = 'allemand' },
			es = { code = 'es', nom = 'espagnol' },
			it = { code = 'it', nom = 'italien'	 },
			la = { code = 'la', nom = 'latin'	 },
--			['rtl script'] = { Arab = true }, -- debug : risque d'anomalie, anomaly risc
		}
		dataLangue.anglais = dataLangue.en
		dataLangue['français'] = dataLangue.fr
		dataLangue.francais = dataLangue.fr
		dataLangue.allemand = dataLangue.de
		dataLangue.espagnol = dataLangue.es
		dataLangue.italien = dataLangue.it
	end
	return dataLangue
end -- function p.get_IETF_fr()

function p.dummy_languages() -- Test dummy languages
	-- https://fr.wikipedia.org/wiki/%C3%89tiquette_d%27identification_de_langues_IETF
	-- https://fr.wikipedia.org/wiki/Module:Langue/Data
	--	pour convertir en code de langue IETF les noms français de langues
	-- https://www.mediawiki.org/wiki/Manual:$wgDummyLanguageCodes
	--	List of language codes that have been renamed to new (correct) codes, or don't correspond to an actual interface language.
	--	array( 'als' => 'gsw', 'bat-smg' => 'sgs', 'be-x-old' => 'be-tarask', 'bh' => 'bho'...
	local dummy_i18n = {
		en = "Module:ControlArgs/I18N", -- english
		es = "Modul:ControlArgs/I18N", -- spanish
		fr = "Module:ControlArgs/I18N", -- french
		Fr = "Module:ControlArgs/I18N", -- error test
		als = "Modulen:ControlArgs/I18N", -- alemanish
		gsw = "Mod-gsw:ControlArgs/I18N", -- unknown
		["bat-smg"] = "Mod-bat-smg:ControlArgs/I18N", -- alemanish
		sgs = "Mod-sgs:ControlArgs/I18N", -- unknown
	}
	local t = '\n* dummy_languages : ' ..  p.ta("isTag", "isKnownLanguageTag(xx)") .. p.ta("isLang", "isSupportedLanguage(xx)") .. p.ta("isBuilt", "isValidBuiltInCode(xx)")
	for lang, modname in pairs(dummy_i18n) do -- Pour tous les parametres connus
		local isTag = mw.language.isKnownLanguageTag(lang)
		local isLang = mw.language.isSupportedLanguage(lang)
		local isBuilt = mw.language.isValidBuiltInCode(lang)
		local langname = mw.language.fetchLanguageName(lang, "en")
		local native = mw.language.fetchLanguageName(lang)
		local space_name = tostring(mw.site.namespaces.Module.name)
		t = t .. '\n**' .. p.ta("lang", lang) .. p.ta("isTag", isTag) .. p.ta("isLang", isLang)
		t = t .. p.ta("langname", langname) .. p.ta("native", native)
	end
	return t
end -- function p.dummy_languages()

-- Verifier la cohérence des tables de traductions
function p.verif_i18n(i18n)
	if type(i18n) ~= "table" then i18n = p.i18n end
	if type(i18n) ~= "table" then return " verif_i18n MISSING. " end
	local nerr, trad, t, err = 0, "", "", ""
	local nbr, list = 0, ""
	--
	-- List any gaps of translations in i18n tables.
	-- Liste cualquier las lagunas traducciones en tablas i18n.
	-- Lister tous les manques de traductions dans les tables i18n.
	local prec_tab, suiv_tab, max, nk = nil, nil, 0, 0
	local lang, prec_lang, suiv_lang, cats = "", "", "", ""
	local all_txts = {}
	for lang, texts in pairs(i18n) do -- Pour toutes les langues et tous les textes à traduire
		suiv_lang = lang -- table suivante de traduction d'une langue
		suiv_tab = texts -- table suivante de traduction d'une langue
		list = list .. lang .. ", "
		nbr = nbr + 1
		for k, v in pairs(texts) do -- Lister tous les textes traduits au moins dans une langue
			all_txts[k] = "x"
		end
		if prec_tab ~= nil and suiv_tab ~= nil then -- pour chaque couple de langues à comparer
			t = t .. "\n* Comparer les langues : '''" .. prec_lang .. "/" .. suiv_lang .. "''', "
			nk = 0
			for k, x in pairs(all_txts) do -- Pour tous les textes à traduire
				trad = suiv_tab[k]
				nk = nk + 1
				if trad == nil then -- and k ~= nil then -- args vers un argument nommé
					err = p.err_add("err_module_miss_i18n_txt", k, suiv_lang)
					t = t .. err .. " " -- .. "<br/>"
					nerr = nerr + 1
				end
			end
			if nk > max then max = nk end
		end
		prec_lang = suiv_lang
		prec_tab = suiv_tab
	end
	if nerr > 0 then
		err = p.err_add("err_module_miss_i18n_count", nerr, max)
		t = t .. "<br/>" .. err .. " "
		cats = cats .. p.cat_add("err_module_miss_i18n_cat") -- generate one category
--		cats = cats .. p.cat_add("cat_internal_error")
	end
	-- tester vr le nombre total de variables de traductions
	local st, vr, fn, tb = p.testable_lister(i18n, "i18n")
	if vr < 33 then
		err = p.err_add("err_module_miss_i18n_mini", vr)
		t = t .. "<br/>" .. err .. " "
		cats = cats .. p.cat_add("err_module_miss_i18n_cat") -- generate one category
--		cats = cats .. p.cat_add("cat_internal_error")
	end
	t = t .. p.str_vars("languages_nbr_and_list", nbr, list) -- generate one category
	return t, cats
end -- function p.verif_i18n(i18n)

-- Modifier ou ajouter des langues et champs de traductions d'une table ou d'un module
function p.add_i18n(i18n, t)
	-- p.add_i18n(p.i18n_args) -- fusionner les traductions d'une table i18n
	-- p.add_i18n("ControlArgs/I18N") -- fusionner les traductions d'un module I18N
	local I18N, moduleI18N, localnamespace_Module
	t = t or "add_i18n : "
	if type(i18n) == "string" then -- Si les langues sont dans un module
		-- Verifier que les traductions sont disponibles.
		if type(p.module_name) ~= "string" then p.module_name = "ControlArgs" end
		-- "Module" namespace translated to local language :
		localnamespace_Module = tostring(mw.site.namespaces.Module.name)
		moduleI18N = localnamespace_Module .. ":" .. i18n -- Module:ControlArgs/I18N
	--	moduleI18N = i18n -- Module:ControlArgs/I18N
		t = t .. p.ta("localnamespace_Module", localnamespace_Module) .. p.ta("p.module_name", p.module_name)
		t = t .. p.ta("i18n", i18n) .. p.ta("moduleI18N", moduleI18N)
		I18N = require(moduleI18N) -- integrer le module I18N
		if type(I18N) == "table" then
			i18n, txt = p.add_i18n(I18N.i18n)
			t = t .. p.ta("require(moduleI18N)", I18N) .. p.ta("require(moduleI18N).i18n", i18n)
			if type(i18n) == "table" then
				p.i18n = i18n
			end
		end
	end
	if type(i18n) ~= "table" then return p.i18n, "rien a importer." end
	local an, ln = 0, 0
	for lng, argmts in pairs(i18n) do -- Pour toutes les langues à importer
		if p.i18n[lng] then -- la langue existe déja, y ajouter ou y remplacer les champs importés
			t = t .. p.str_vars(", '''Langue : %1''' ", lng)
			ln = ln + 1
			for argn, val in pairs(argmts) do -- Pour tous les champs importés
				p.i18n[lng][argn] = val -- ajouter ou remplacer un champs et sa traduction
				t = t .. p.str_vars(", %1 ", argn)
				an = an + 1
			end
		else -- ajouter la table et tous ses champs si elle n'est pas encore dans p.i18n
			if mw.language.isKnownLanguageTag(lng) then
				p.i18n[lng] = i18n[lng]
			end
		end
	end
	t = t .. p.str_vars(", Comptes des ajouts : '''langues=%1 champs=%2''' ", ln, an)
	return p.i18n, t, ln, an
end -- function p.add_i18n(i18n, t)

-- en : initialize or change the user and the wiki languages and their tables
-- es : inicializar o cambiar el idiomas del usuario y del wiki y su tablas
-- fr : initialiser ou modifier la langue de l'utilisateur et du wiki et leurs tables
function p.init_user_lang(user_lang, wiki_lang)
	t = "\n* init_user_lang : asked user_lang = " .. tostring(user_lang) .. " user_lang = " .. tostring(wiki_lang)
	-- wiki_lang ok if i18n ok, else wiki language
	if type(wiki_lang) ~= "string" then wiki_lang = nil end
	if not p.i18n[wiki_lang] then wiki_lang = nil end
	wiki_lang = wiki_lang or tostring(mw.language.getContentLanguage().code)
	--
	-- user_lang ok if i18n ok, else wiki language
	if type(user_lang) ~= "string" then user_lang = nil end
	if not p.i18n[user_lang] then user_lang = nil end
	user_lang = user_lang or wiki_lang
	if not mw.language.isSupportedLanguage(user_lang) then
		-- Error if the language is not a wikipedia language
		-- Erreur si la langue n'est pas une des langues de wikipedia
		t = t .. p.err_add("err_lang_not_exist", " ", user_lang)
--		t = t .. p.cat_add("err_module_with_error") -- generate one category
	end
	--
	-- Activate the language for errors and messages. Activer la langue pour les erreurs et messages
	CA.user_lang = user_lang
	CA.user_translations = p.i18n[CA.user_lang]
	-- Activate the language for categories. Activer la langue pour les catégories.
	CA.wiki_lang = wiki_lang
	CA.wiki_translations = p.i18n[CA.wiki_lang]
--	t = t .. CA.ta("\n* CA.user_lang", CA.user_lang) .. CA.ta("example", CA.user_translations["err_module_with_error"])
--	t = t .. CA.ta("\n* CA.wiki_lang", CA.wiki_lang) .. CA.ta("example", CA.wiki_translations["err_module_with_error"])
	return t .. "<br>"
end -- function p.init_user_lang(user_lang, wiki_lang)

function p.init_spaces()
--	local frame = mw.getCurrentFrame()
--	local title = mw.title.getCurrentTitle()
--	p.current_space = frame:preprocess("{{ns:0}}") -- Module namespace from system
--	p.current_space = title.nsText -- Module namespace from system
	p.current_space = mw.site.namespaces.name -- present namespace from system
--	p.module_space = frame:preprocess("{{ns:Module}}") -- Module namespace from system
	p.module_space = tostring(mw.site.namespaces.Module.name)
--	p.template_space = frame:preprocess("{{ns:Template}}") -- Template namespace from system
	p.template_space = tostring(mw.site.namespaces.Template.name)
--	p.author_space = frame:preprocess("{{ns:Author}}") -- Category namespace from system
	p.author_space = tostring(mw.site.namespaces.Author.name)
--	p.category_space = frame:preprocess("{{ns:Category}}") -- Category namespace from system
	p.category_space = tostring(mw.site.namespaces.Category.name)
end -- function p.init_spaces(frame)

------------------------------------------------------------
-- Manage errors and messages. Administrar errores y mensages. Gérer les erreurs et messages.
------------------------------------------------------------

p.errors_list = {} -- Table to collect errors and messages
p.erron = true -- Activated or not errors. Errores activado o no. Erreurs activées ou non.

-- Add a message, error or categary to le lists.
function p.error_add(typ, ref, v1, v2, v3, v4, v5)
	--	p.err_add("err_value_re_defined", k, key, xyz)
	if not p.erron then return "" end
	local msg = { ["typ"] = typ, ["ref"] = ref, ["v1"] = v1, ["v2"] = v2, ["v3"] = v3, ["v4"] = v4, ["v5"] = v5 }
	table.insert(p.errors_list, msg)
	local str = p.str_vars(msg.ref, msg.v1, msg.v2, msg.v3, msg.v4, msg.v5)
	local res = ""
	if msg.typ == "msg" then
		res = '<br/>⦁ ' .. p.message_color(str)
	end
	if msg.typ == "err" then
		res = '<br/>⦁ ' .. p.error_color(str)
	end
	return res
end -- function p.error_add(typ, ref, v1, v2, v3, v4, v5)

function p.err_add(ref, v1, v2, v3, v4, v5)
	return p.error_add("err", ref, v1, v2, v3, v4, v5)
end

function p.msg_add(ref, v1, v2, v3, v4, v5)
	return p.error_add("msg", ref, v1, v2, v3, v4, v5)
end

function p.errors_lister(title, v1, v2, v3)
	local res, msgref = "", ""
--	res = res .. p.testable_lister(p.errors_list, "p.errors_list")
	local mwtitle = mw.title.getCurrentTitle()
	local page = tostring(mwtitle.nsText) .. ":" .. tostring(mwtitle.text)
	if type(title) ~= "string" then title = "err_error_list_header" end
	res = res .. '\n*' .. p.str_vars(title, page, v1, v2, v3) -- .. ' - ' .. page
	local n = 0
	for k, msg in ipairs(p.errors_list) do
		msgref = p.str_vars(msg.ref, msg.v1, msg.v2, msg.v3, msg.v4, msg.v5) -- texte traduit ou direct
		if msg.typ == "msg" then
			res = res .. '<br/>⦁ ' .. p.message_color(msgref)
		end
	end
	for k, msg in ipairs(p.errors_list) do
		msgref = p.str_vars(msg.ref, msg.v1, msg.v2, msg.v3, msg.v4, msg.v5) -- texte traduit ou direct
		if msg.typ == "err" then
			res = res .. '<br/>⦁ ' .. p.error_color(msgref)
			n = n + 1
		end
	end
	if n > 0 then
		p.cat_add("err_module_with_error") -- generate one category
	end
	return res
end -- function p.errors_lister(title, v1, v2, v3)

------------------------------------------------------------
-- Manage categories. Administrar categorías. Gérer les catégories.
------------------------------------------------------------

function p.catGen(ref, v1, v2, v3, v4, v5)
	-- add a category to the categories_list
	table.insert(p.categories_list, { ["typ"] = "cat", ["ref"] = ref, ["v1"] = v1, ["v2"] = v2, ["v3"] = v3, ["v4"] = v4, ["v5"] = v5 })
end

-- Record in categories_list and genrate the wikitext of a category
function p.cat_add(ref, v1, v2, v3, v4, v5)
	-- add a category to the categories_list
	local cat = { ["typ"] = "cat", ["ref"] = ref, ["v1"] = v1, ["v2"] = v2, ["v3"] = v3, ["v4"] = v4, ["v5"] = v5 }
	local doit = true
	for k, cat2 in ipairs(p.categories_list) do
		-- If the new category is already registered and without variables, do not add it.
		-- Si la nouvelle catégorie est déjà enregistrée et sans variables, ne pas l'ajouter.
		if (cat2.ref == ref) and not v1 and not v2 and not v3 and not v4 and not v5 then doit = false end
	--	if cat2 and cat2.ref and cat2.ref == ref and table.maxn(cat2) < 3 and table.maxn(cat) < 3 then doit = false end
	end
	if doit then table.insert(p.categories_list, cat) end
	--
	c = p.catView or ""
	local wiki_catspace = CA.wiki_translations.category or mw.site.namespaces.Category.name
	local user_catspace = CA.user_translations.category or mw.site.namespaces.Category.name
	local user_cat = p.string_vars(CA.user_translations, cat.ref, cat.v1, cat.v2, cat.v3, cat.v4, cat.v5)
	local wiki_cat = p.string_vars(CA.wiki_translations, cat.ref, cat.v1, cat.v2, cat.v3, cat.v4, cat.v5)
	user_catspace = "" -- without "Category" word
	local res = " [[" .. c .. wiki_catspace .. ":" .. wiki_cat ..  "|" .. user_catspace .. " " .. user_cat .. "]] "
	return res
end -- function p.cat_add(ref, v1, v2, v3, v4, v5)

-- Generate categories from plural values in only one argument
function p.catGroup(groupCat, groupList) -- generate some categories
	-- catGroup("Country %1", "France,Italie") -> [[Category:Country France]] [[Category:Country Italie]]
	if type(groupCat) ~= "string" then groupCat = "%1" end
	if type(groupList) ~= "string" then return "" end
	local cats = ""
	local t = ""
	t = t .. CA.ta("groupList", groupList)
	local splitxt = mw.text.split(groupList, ",", true)
--	t = t .. " splitxt = " .. table.concat(splitxt, "+")
	for str in mw.text.gsplit(groupList, ",", true) do
	--	t = t .. " , s=" .. p.cat_add(groupCat, str)
		cats = cats .. p.cat_add(groupCat, str)
	end
	return cats, t
end -- function p.catGroup(groupCat, groupList)

-- generate the wikitext of the list of categories to only display them
function p.categories_lister(c)
	local res = "\n* Catégories : "
	local wiki_cat = ""
	local user_cat = ""
	if p.option(":", c) then p.catView = ":" else p.catView = "" end
	-- c can replace catView to enforce the documentation or the categorisation
	-- c peut remplacer catView pour forcer la documentation ou la catégorisation
	c = c or p.catView or ""
--	local wiki_catspace = mw.site.namespaces.Category.name
	local user_catspace = CA.user_translations.category
	local wiki_catspace = CA.wiki_translations.category
	for k, cat in ipairs(p.categories_list) do
		user_cat = p.string_vars(CA.user_translations, cat.ref, cat.v1, cat.v2, cat.v3, cat.v4, cat.v5)
		wiki_cat = p.string_vars(CA.wiki_translations, cat.ref, cat.v1, cat.v2, cat.v3, cat.v4, cat.v5)
		user_catspace = "" -- without "Category" word
		res = res .. " [[" .. c .. wiki_catspace .. ":" .. wiki_cat ..  "|" .. user_catspace .. " " .. user_cat .. "]] "
	end
	-- Category namespaces = 14 Category
	-- https://en.wikipedia.org/wiki/IETF_language_tag
	-- https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
	return res
end -- function p.categories_lister(c)

-- generate the wikitext of categories to realy categorize them
function CA.categorizer(c)
	local res = ""
	local wiki_cat = ""
--	if p.option(":", c) then p.catView = ":" else p.catView = "" end
	-- Category namespaces = 14 Category
	-- c can replace catView to enforce the documentation or the categorisation
	-- c peut remplacer catView pour forcer la documentation ou la catégorisation
	c = c or p.catView or ""
	local wiki_catspace = CA.wiki_translations.category
	for k, cat in ipairs(p.categories_list) do
		wiki_cat = p.string_vars(CA.wiki_translations, cat.ref, cat.v1, cat.v2, cat.v3, cat.v4, cat.v5)
		res = res .. "[[" .. c .. wiki_catspace .. ":" .. wiki_cat ..  "]]"
	end
	return res
end -- function CA.categorizer(c)

-- Initialize the categories list. Initialise la liste des categories.
function p.categories_init(catName, catText) -- initialize the category list
	local frame = mw.getCurrentFrame()
	-- p.category_space = frame:preprocess("{{ns:Category}}") -- Category namespace from system, translated
	-- "Category" namespace translated to local language :
	p.category_space = tostring(mw.site.namespaces.Category.name)
	p.categories_list = {} -- init the collect of categories
	return
end

function p.cat_add_test(tst) -- tester les categories
	local cat, t, c = "", "", ":"
	tst = tst or "\n\n* Test des catégories par '''cat_add''' : "
	p.categories_init()
	--
	cat, t = p.cat_add("fausse catégorie", c)
	tst = tst .. (t or "")
	--
	local catName = ""
	cat, t = p.cat_add(catName, catName, c)
	tst = tst .. (t or "")
	--
	catName = p.str_vars("L'année %1 re-nommée", 2000)
	cat, t = p.cat_add("cat_name_number", catName, c)
	tst = tst .. (t or "")
	--
	catName = p.str_vars("cat_name_number", 2002)
	cat, t = p.cat_add(catName, catName, c)
	tst = tst .. (t or "")
	--
	catName = p.str_vars("cat_name_number", 2011)
	cat, t = p.cat_add(catName, c)
	tst = tst .. (t or "")
	--
	tst = tst .. "\n\n* Test des catégories par '''catGroup''' : "
	--
	cat, t = CA.catGroup("language_cat", "french,italian,chinese") -- |language=french,italian,chinese
	tst = tst .. (t or "")
	--
	cat, t = CA.catGroup("occupation_cat", "Académiciens,Personnalités politiques") -- |occupation=Académiciens,Personnalités politiques
	tst = tst .. (t or "")
	--
	tst = tst .. "\n\n* Test catégories '''categories_lister''' : " .. p.categories_lister(":") -- generate the categories wikitext
	return tst
end -- function p.cat_add_test(tst)

------------------------------------------------------------
-- Manage options. Administrar opciones. Gérer les options.
------------------------------------------------------------

--	Options de maitrise du fonctionnement de ce module

p.invoke_options = "" -- Options normales venant du modèle. Aucune par defaut. Normal options from the template.
	--	In the template : options = "params docview docmin docmax docdef docnotice docafter docline docsrc"

p.mode_options = "" -- Options de debug du module par edit. Aucune par defaut.
	-- p.mode_options = "unitest debug noerr erron params docview nobox nocat docin docmax docnotice docdef docline docsrc notices "
	-- p.mode_options change only by editing this module code or the calling module. Empty default value.
	-- p.mode_options change n'est modifié que par ce module ou celui qui l'appele. Valeur par defaut vide.

p.used_options = {} -- table to collect tested options then list them at end of tests

function p.option(key, opt)
	-- if option("nocat") then cat = "" end -- utilisation exemple simple
	-- Si le mot key est parmi les mots options, repondre true
	-- Chercher dans invoke_options, mode_options ou opt, voir ci-dessous
	-- p.options = " : docdata docmin docdef docmax docline docview docsrc docafter docnotice " -- for documentation
	-- p.options = " erron noerr nobox nocat " -- without normal result
	-- p.options = " debug tests en es fr " -- for debug or enforce language
	-- Veiller à toujours séparer les mots par des espaces
	-- Les identifiants de langues permettent de forcer certaines langues.
	-- Les erreurs n'apparaissent que dans les espaces de noms Modèle ou Module, en attendant la réalisation du Bug 51660.
	if type(key) ~= "string" then return false end
	local options = "  " .. tostring(p.invoke_options) .. "	 "
	if type(opt) == "string"
		then options = options .. "	 " .. opt .. "	" -- options du modèle et de l'appel si définies
		else options = options .. "	 " .. p.mode_options .. "	"
	end -- options du modèle et de debug sinon
	-- chercher les mots clefs exacts et non ceux inclus dans un autre mot
	local key2 = " " .. key .. " "
	-- Le mot cle est-il parmi les mots options ?
	local yes = string.find(options, key2) and true
	--
	-- collect options tested along the execution of the module
	if yes then p.used_options[key] = "a"
	else p.used_options[key] = "x" end
	--
	return yes -- ( yes ~= nil )
end -- function p.option(key, opt)

function p.init_options( opt )
	-- p.invoke_options = init_options(args.options)
	-- p.invoke_options = init_options("fr params docview docmin docmax docdef docnotice docafter docline docsrc")
	--
	if (type(opt) == "string") then p.invoke_options = opt end --  and (new ~= "")
	--
	-- Early effects on options which modify other ones.
	-- Effets précosses pour des options qui agissent sur d'autres options.
	-- p.options = " : docdata docmin docdef docmax docline docview docafter docnotice docsrc" -- for documentation
	-- p.options = " erron noerr nobox nocat " -- without normal result
	-- p.options = " debug tests en es fr " -- for debug or enforce language
	if p.option(":") then p.catView = ":" else p.catView = "" end
	if p.option("noerr") then p.erron = false end
	if p.option("erron") then p.erron = true end
	-- If an option is a language to enable this language.
	-- Si una opción es un lenguaje para habilitar esta lengua.
	-- Si une option est une langue, activer cette langue.
	for lang, tab in pairs(p.i18n) do
		if p.option(lang) then
			p.init_lang(lang)
		end
	end
	return opt
--	local t = '\n* dummy_languages : ' ..  p.ta("isTag", "isKnownLanguageTag(xx)") .. p.ta("isLang", "isSupportedLanguage(xx)") .. p.ta("isBuilt", "isValidBuiltInCode(xx)")
end -- function p.init_options(new)

function p.used_options_list(t)
	-- List of used options after collect them
	t = t or ""
	t = t .. CA.ta("\n* Options linked to the mode. Options liées au mode : CA.mode_options", CA.mode_options)
	t = t .. CA.ta("\n* Options linked to the page. Options liées à la page : CA.invoke_options", CA.invoke_options)
	--
	t = t .. "\n* Options '''activated''' or only tested. Options '''activées''' ou seulement testées. : "
	for key, x in pairs(p.used_options) do
		if x == "a" then t = t .. " , '''" .. key .. "''' "
		else t = t .. " , " .. key end
	end
--	t = t .. "\n* import_arguments_track : " .. CA.import_arguments_track
	return t
end -- function p.used_options_list(t)

function p.wordstotable(txt, opt) -- convertit un texte en table de mots
	local t = ""
	local tab = {}
	function inserer(ti)
		if ti ~= "" then table.insert(tab, ti.."") end
	end
	local xyz = string.gsub( txt, "(%S*%-*%S*)", inserer ) -- "(%w*%-*%'*%w*)", "(%S*%-*%S*)"
	for key, val in pairs(tab) do -- Pour tous les mots
		t = t .. " ( " .. tostring(key) .. " = " .. tostring(val) .. " ) "
	end
	t = "\n* wordstotable txt = " .. tostring(xyz) .. " " .. t
	return tab, t, opt
end -- function p.wordstotable(txt, opt)

------------------------------------------------------------
-- Argts : Manage arguments. Gestione argumentos. Gérer les arguments.
------------------------------------------------------------

function p.levenshtein_1(search, word, max)
	-- search = mot cherché dans la liste
	-- word = un des mot de la liste
	-- p.max_nearest_argument = 3 -- Limite de differences des arguments proposables à l'utilisateur
--	if not max then max = p.max_nearest_argument end
--	if not max then max = 3 end
	diffmaxi = p.similar_args_diffmaxi( string.len(search) )
	local len1, len2, lev, tlev, t, diff
--	t = t .. "<br/>- diff: " .. p.ta("mot1", mot1) .. p.ta("mot2", mot2) .. p.ta("diff", diff)
	t = "<br/>levenshtein : "
	if (not search ) or (not word) then
		diff = 99
		t = t .. p.ta("diff", diff) .. " no word. "
	elseif search == word then
		diff = 0
		t = t .. p.ta("diff", diff) .. " , " .. search .. " = " .. word .. " "
	else
	--	len1 = string.len(search)
	--	len2 = string.len(word)
		lev, tlev = p.levenshtein(tostring(search), tostring(word))
		if (lev <= diffmaxi) then
			t = t .. p.ta("diffmaxi", diffmaxi) .. " >= " .. p.ta("lev", lev) .. " '''" .. search .. " ==> " .. word .. "''' "
		else
			t = t .. p.ta("diffmaxi", diffmaxi) .. " >= " .. p.ta("lev", lev) .. " " .. search .. " / " .. word .. " "
		end
	end
	return diff, t, search, word
end -- function p.levenshtein_1(search, word, max)

function p.levenshtein_test( res, c)
	res = res .. "\n* " .. p.str_vars("max_nearest_argument_msg", p.max_nearest_argument or 3)
	local errors = ""
	local n, t = p.levenshtein_1( "nom", "nom")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "nom", "Nom")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "top", "pot")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "ami", "amis")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "nom", "name")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "m", "mu")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "m", "mur")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "mur", "m")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "c", "C")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "c", "cf")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "c", "long")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "xxx", "")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "", "xyz")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "xxx", "xyz")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "prénom", "Prenom")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "catégorie", "Category")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "description", "Description")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "anneeDeces", "anneeNaissance")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "anoNacimiento", "anneeNaissance")
	res = res .. tostring(t)
	local n, t = p.levenshtein_1( "avant-après", "après-avant")
	res = res .. tostring(t)
	if errors ~= "" then res = res .. "\n* '''levenshtein_test''' errors = " .. p.error_color(errors) end
	return res
end -- function p.levenshtein_test( res, c)

-- Maximum number of different letters between 2 argument names
-- Número máximo de letras diferentes entre 2 nombres de argumento
-- Nombre maximum de lettres différentes entre deux noms d'arguments
function p.similar_args_diffmaxi(length, t) -- diffmaxi from length of arg arglingual name
	local coef = CA.constants.near_word_search_diff_coef or 0.30
	local constant = CA.constants.near_word_search_diff_const or 0.32
	local diffmaxi = math.floor( coef * length + constant )
	if t then t = t .. tostring(coef) .. " * length + " .. tostring(constant) end
	return diffmaxi, t
end -- function p.similar_args_diffmaxi(length, t)

-- calcule la distance de Levenshtein entre deux mots (ASCII), -- voir fr:Module:Classification ReptileDB Hexasoft
function p.levenshtein(mot1, mot2)
	-- eviter les exceptions
	local cout = 0
	mot1 = tostring(mot1)
	mot2 = tostring(mot2)
	local len1 = string.len(mot1)
	local len2 = string.len(mot2)
	local lev = 0
	local t = "<br/>lev: " .. p.ta("mot1", mot1) .. p.ta("mot2", mot2)
	if (type(mot1) ~= "string") or (type(mot2) ~= "string") or (mot1 == "") or (mot2 == "") then
		lev = len1 + len2
		return lev, t .. p.ta("lev", lev)
	end
	-- cas simple
	if (mot1 == mot2) then
		lev = 0
		return lev, t .. p.ta("lev", lev)
	end
	local d = {}
	for i = 1, len1+2 do -- for i = 1, len1-1+1 do
		d[i] = {}
		--	d[i][1] = 0 -- d[i][1] = i
		for j = 1, len2+2 do
			--	d[i][j] = {}
			d[i][j] = 0 -- d[1][j] = j
		end
	end
	-- on simule un tableau à deux dimensions
	for i = 2, len1+1 do -- for i = 1, len1-1+1 do
		--	d[i] = {}
		d[i][1] = i-1 -- d[i][1] = i
	end
	for j = 2, len2+1 do
		d[1][j] = j-1 -- d[1][j] = j
	end
	for i = 2, len1+1 do -- for i = 2, len1+1 do
		for j = 2, len2+1 do -- for j = 2, len2+1 do
			-- on récupère les deux caractères
			local c1 = string.byte(mot1, i-1)
			local c2 = string.byte(mot2, j-1)
			if (c1 == c2) then
				cout = 0
				d[i][j] = d[i-1][j-1]
			else
				cout = 1
				d[i][j] = math.min(d[i-1][j], d[i][j-1], d[i-1][j-1]) + 1
			end
			--	d[i][j] = math.min(d[i-1][j]+1, d[i][j-1]+1, d[i-1][j-1]+cout)
		end
	end
	local lev = d[len1+1][len2+1] -- return d[len1-1][len2] - 1
	return lev, t .. p.ta("lev", lev)
end -- function p.levenshtein(mot1, mot2)

-- Pour un argument inconnu, cherche le nom d'argument le plus proche, parmi les arguments connus traduits
function p.similar_args_list(args_known)
	local list, arglingual = {}, "xxx"
	if type(args_known) ~= "table" then args_known = CA.args_known end
	if type(args_known) ~= "table" then return "similar_args_list", 1 end
	-- faire la liste des arguments possibles, c'est a dire connus
	for key, argm in pairs(args_known) do
		if not tonumber(key) then -- Pour les arguments nommés seulement
			key = tostring(key)
			arglingual = tostring(CA.wiki_translations[key])
			list[key] = arglingual
		end
	end
	return list
end -- function p.similar_args_list(args_known)

-- For an unknown argument, seeking the name of the nearest argument among the known arguments
-- Para un argumento desconocido, buscando el nombre del argumento más cercana entre los argumentos conocidos
-- Pour un argument inconnu, cherche le nom d'argument le plus proche, parmi les arguments connus
function p.similar_args_search(search, list)
	local dist, lengths, tlev = 9, 0
	local trouve1, trouve2, trouve3 = nil, nil, nil
	local min1, min2, min3 = 99, 99, 99
	local diffmaxi = p.similar_args_diffmaxi( string.len(search) )
	local t = t .. ", " .. tostring(diffmaxi) .. " / " .. tostring(length) .. " "
	for key, arglingual in pairs(list) do
		-- Search the most similar and same length. Buscar las más similares y la misma longitud. Chercher le plus ressemblant et la même longueur.
	--	dist = p.levenshtein_1(tostring(cherche), tostring(mot)) -- obsolete
		dist, tlev = p.levenshtein(search, arglingual)
	--	if type(dist) ~= "number" then dist = 9 end
		if (dist <= min1) then
			trouve3 = trouve2
			min3 = min2
			trouve2 = trouve1
			min2 = min1
			min1 = dist
			trouve1 = tostring(arglingual)
		end
	end
	t = t .. "<br/>" .. p.ta("cherche", cherche) .. p.ta("trouve1", trouve1) .. p.ta("min1", min1) .. p.ta("trouve2", trouve2) .. p.ta("min2", min2) .. " " .. t
	if trouve1 and min1 == 0 then t = t .. CA.wikidata_color(p.ta("connu", trouve1)) end
	if trouve1 and min1 <= diffmaxi then t = t .. CA.wikidata_color(p.ta("min1 "..min1.."<="..diffmaxi, trouve1)) end
	if trouve2 and min2 <= diffmaxi then t = t .. CA.wikidata_color(p.ta("min2 "..min2.."<="..diffmaxi, trouve2)) end
	if trouve3 and min3 <= diffmaxi then t = t .. CA.wikidata_color(p.ta("min3 "..min3.."<="..diffmaxi, trouve3)) end
	return trouve1, min1, trouve2, min2, t
end -- function p.similar_args_search(search, list)

--	t = p.similar_args_test1( t, "nomm", "digit")
function p.similar_args_test1( t, search, liste)
	local args_list = p.similar_args_list(CA.args_known)
	local trouve1, min1, trouve2, min2 = p.similar_args_search(search, args_list)
--	local trouve1, min1, trouve2, min2 = "aaa", 1, "bbb", 22
	t = t .. "\n* similar_args_test1 : " .. CA.ta("search", search) .. CA.ta("trouve1", trouve1) .. CA.ta("min1", min1) .. CA.tam("trouve2", trouve2) .. CA.tam("min2", min2)
	return t or " similar_args_test1 "
end -- function p.similar_args_test1( t, search, liste)

function p.similar_args_test( t, args_known)
	if type(args_known) ~= "table" then args_known = CA.args_known end
	local err = CA.verify_args_tables(args_known, CA.args_source)
	if err then return err end
	--
	local key, argsyn, arglingual, txt
--	local coef = CA.constants.near_word_search_diff_coef
--	local constant = CA.constants.near_word_search_diff_const
	t = t .. "\n\n:* Formule de calcul des mots proches : "
	local diffmaxi
	diffmaxi, t = p.similar_args_diffmaxi(10, t .. "diffmaxi = ")
	t = t .. "\n\n:* List of diffmaxi / lengths : "
	for length = 1, 16 do -- For all lengths
	--	local diffmaxi = math.floor( coef * length + constant )
		diffmaxi = p.similar_args_diffmaxi(length)
		t = t .. ", " .. tostring(diffmaxi) .. " / " .. tostring(length) .. " "
	end
	t = t .. "\n\n:* List of known arguments and '''synonyms''' : "
	local txt, lingual = "", ""
	local ref_words = { }
	for key_known, argm in pairs(args_known) do -- Pour tous les paramètres connus
		if argm.syn == 1 then
			key = argm.keyword
			argsyn = key_known .. ">" -- synonym argument
		else
			key = key_known
			argsyn = "" -- synonym argument
		end
	--	CA.user_translations = p.i18n[lang] or CA.user_translations
	--	CA.wiki_translations = mw.language.getContentLanguage().code
		lingual = CA.wiki_translations[key] or "-" -- importer un argument source
		txt = argsyn .. key .. "/" .. lingual
		if argm.syn == 1 then
			t = t .. ", '''" .. txt .. "''' " -- '''synonyms'''
		else
			t = t .. ", " .. txt .. " "
		end
		ref_words[key] = { }
		ref_words[key].argmt = key
		ref_words[key].lingual = lingual
	end
	t = t .. "\n:* Test similar arguments 1."
	t = p.similar_args_test1( t, "anneedece", {["a"]="but", ["b"]="porter", ["c"]="anneedeces"})
	t = t .. "\n:* Test similar arguments 2."
	t = p.similar_args_test1( t, "porte", {["a"]="but", ["b"]="porter", ["c"]="pot"})
	return t
end -- function p.similar_args_test( t, args_known)

------------------------------------------------------------
-- Datas wikidata from mw.wikibase
------------------------------------------------------------

function p.import_wikidata(args_known, elem)
-- wikidata structure p.father = mw.wikibase.label( "Q" .. entity.claims.p107[0].mainsnak.datavalue.value["numeric-id"])
	if type(args_known) ~= "table" then args_known = CA.args_known end
	local t, adr, val, proplabel = "", nil, nil, nil
	local wd = {}
	local wd_mng = {} -- wikidata manager
	if elem then -- Le 2013-06-19 acces restreint par Lua pour un autre élément
		-- https://bugzilla.wikimedia.org/show_bug.cgi?id=49805
		-- Bug 49805 - Allow mw.wikibase.getEntity and getProperty to access arbitrary Wikidata items
		-- Reported: 2013-06-19 10:52 UTC by Rical
	--	wd_mng.wd_error = "wd_elem"
		wd_mng.wd_elem = elem
	--	t = t .. CA.ta("wd_error", wd.wd_error)
		t = t .. CA.ta("wd_elem", wd_mng.wd_elem .. ", ne fonctionne que sur la page courante, voir [https://bugzilla.wikimedia.org/show_bug.cgi?id=47930 bug 47930]   .")
		wd_mng.t = t
		p.args_wikidata = wd
		return wd, t, wd_mng
	end
	wd_mng.wd_base = mw.wikibase
	if not wd_mng.wd_base then -- Wikidata disponible ?
		wd_mng.wd_error = "wd_base"
		t = t .. CA.ta("wd_error", wd_mng.wd_error)
		wd_mng.t = t
		p.args_wikidata = wd
		return wd, t, wd_mng
	end
	wd_mng.wd_entity = mw.wikibase.getEntityObject( )
	if wd_mng.wd_entity then -- Page Wikidata disponible ?
		if wd_mng.wd_entity.claimRanks then
			wd_mng.wd_claimRanks = wd_mng.wd_entity.claimRanks
			wd_mng.wd_RANK_PREFERRED = wd_mng.wd_entity.claimRanks.RANK_PREFERRED
			wd_mng.wd_RANK_NORMAL = wd_mng.wd_entity.claimRanks.RANK_NORMAL
			wd_mng.wd_RANK_DEPRECATED = wd_mng.wd_entity.claimRanks.RANK_DEPRECATED
			-- https://www.mediawiki.org/wiki/Extension:WikibaseClient/Lua#mw.wikibase.entity.claimRanks
			-- Return the normal ranked claims with the property id P5
			-- entity:formatPropertyValues( 'P5', { mw.wikibase.entity.claimRanks.RANK_NORMAL } )
			-- Return all claims with id P123 (as the table passed contains all possible claim ranks)
			-- entity:formatPropertyValues( 'P123', mw.wikibase.entity.claimRanks )
			-- mw.wikibase.entity.claimRanks = RANK_PREFERRED, RANK_NORMAL, RANK_DEPRECATED
		end
		wd_mng.sitelink = wd_mng.wd_entity:getSitelink( )
		wd_mng.label = wd_mng.wd_entity:getLabel( ) -- Returns a string, like "Berlin" with 'de'
		wd_mng.props = wd_mng.wd_entity:getProperties() -- or {} Returns a table like: { "P123", "P1337" }
		wd_mng.props_maxn = tostring(table.maxn( wd_mng.props ) )
		wd_mng.props_txt = "T " .. mw.text.listToText( wd_mng.props )
		--
		wd_mng.props_list = " "
		for i, pp in ipairs(wd_mng.props) do -- Properties list
			wd_mng.formatPropertyValues = wd_mng.wd_entity:formatPropertyValues(  pp )
			if wd_mng.wd_claimRanks then
				wd_mng.formatPropertyValues = wd_mng.wd_entity:formatPropertyValues(  pp, { wd_mng.wd_claimRanks } )
			end
			val = wd_mng.formatPropertyValues.value
			proplabel = wd_mng.formatPropertyValues.label
			wd_mng.props_list = wd_mng.props_list .. " , " .. i .. "=" .. pp .. "=" .. CA.ta(proplabel, val)
			-- .. "/" .. CA.ta(proplabel, wd_mng.formatPropertyNORMAL)
		end
	else -- entity introuvable pour la page
		wd_mng.wd_error = "wd_entity"
		t = t .. CA.ta("wd_error", wd.wd_error)
		wd_mng.t = t
		p.args_wikidata = wd
		return wd, t, wd_mng
	end
	for key, pp in pairs(args_known) do -- Pour tous les paramètres connus
		if pp.prop then
			if pp.prop == "label" then
				val = wd_mng.label
			elseif pp.prop == "sitelink" then
				val = wd_mng.sitelink
			elseif pp.prop == "entityid" then
				val = wd_mng.wd_entity.id
			else
				wd_mng.formatPropertyValues = wd_mng.wd_entity:formatPropertyValues( "P" .. pp.prop )
				-- Returns a table like: { value = "Formatted claim value", label = "Label of the Property" }
				if wd_mng.wd_claimRanks then
					wd_mng.formatPropertyValues = wd_mng.wd_entity:formatPropertyValues(  pp, { wd_mng.wd_claimRanks } )
				end
				val = wd_mng.formatPropertyValues.value
				proplabel = wd_mng.formatPropertyValues.label
			end
			if pp.format == "year" then
				val = mw.ustring.sub( val, -4, -1 )
			end
			wd[key] = val
			t = t .. CA.ta(key, val) .. CA.ta(key, wd_mng.formatPropertyNORMAL)
		end
	end
--	wd.lastname = wd.label
	if wd_mng.wd_error then -- Signaler une erreur
		if wd_mng.wd_error == "wikidata_props" then err = p.str_vars("err_wikidata_error", "wikidata_props") end
		if wd_mng.wd_error == "wd_base" then err = p.str_vars("err_wikidata_wikibase") end
		if wd_mng.wd_error == "wd_entity" then err = p.str_vars("err_wikidata_getEntity", wd_mng.wd_entity) end
		if wd_mng.wd_error == "wd_property" then err = p.str_vars("err_wikidata_property", wd_mng.wd_property) end
		if wd_mng.wd_error == "wd_elem" then err = p.str_vars("err_wikidata_getElement", wd_mng.wd_elem) end
		err = p.err_add(err)
		t = t .. err
		local err_wikidata_cat = p.cat_add("err_wikidata_cat")
	end
	wd_mng.t = t
	CA.args_wikidata = wd
	return wd, t, wd_mng
end -- function p.import_wikidata(args_known, elem)

function CA.Th(t) return '\n{| class="wikitable alternative center" | ' .. tostring(t or " ") end -- Table header
-- ! style="text-align:left;"| Item
-- {| class="wikitable" style="text-align: center; color: green;"
-- {| border="1" style="border-collapse:collapse"
-- {| class="wikitable sortable" border="1" mw-collapsible mw-collapsed"
function CA.Tc(t) return '\n! scope="col" | ' .. tostring(t or " ") end -- Table row
function CA.Tr(t) return "\n|- " .. tostring(t or " ") end -- Table row
function CA.Td(t) return "\n| " .. tostring(t or " ") end -- Table data
function CA.Te(t) return "\n|}" end -- Table end

function p.dropdown_func(if_view, title, content, ...)
	-- p.dropdown_func(1, "Comptages des contenus de tables", CA.tables_comptes)
	-- p.dropdown_func(1,  "Détails des arguments", CA.testable_lister, CA.args_source, "CA.args_source")
	local t = ""
	local func = ""
	if type(content) == "string" then -- optional arguments
		t = t .. content
	else
		func = content
		if type(func) == "function" then -- optional arguments
			t = t .. func(...)
		end
	end
	return CA.dropdown_box(if_view, title, t, nil, "===")
end -- function p.dropdown_func(if_view, title, content, ...)

-- Extract a part of date following a pre-defined format which starts with separator
function p.date_to_part_old(date, format, part)
	-- local t, err = p.date_to_part(a.birthyear, "dd mmmm yyyy", "yyyy")
	if type(date) ~= "string"
	or type(format) ~= "string"
	or type(part) ~= "string"
	then return nil, "date_to_part_call_err" end
	local t, err, found
	local sep = mw.ustring.sub(format, 1, 1)
	local format = mw.ustring.sub(format, 2, -1)
	local format_split = mw.text.split(format, sep)
	local date_split = mw.text.split(date, sep)
	for i, format_part in ipairs(format_split) do
		if format_part == part then t = date_split[i] end
	end
	if not t then err = "date_to_part_err_not_found" end
	return t, err
-- A faire : Titus Livius (Q2039), format de dates : P569 = date of birth = 59 BCE, P570 = date of death = 17
end -- function p.date_to_part_old(date, format, part)

-- Extract a part of date following a pre-defined format which starts with separator
function p.date_split(date, format)
	-- local dd, mmmm, yyyy, era = p.date_split(a.birthdate, " dd mmmm yyyy")
	local dd, mmmm, yyyy, era
	local format_split = mw.text.split(format, "%s")
	local split = mw.text.split(date, "%s")
	for i, date_part in ipairs(split) do
		if format_split[i] == "dd" then dd = tonumber(date_part) end
		if format_split[i] == "mmmm" then mmmm = date_part end
		if format_split[i] == "yyyy" then yyyy = tonumber(date_part) end
		if format_split[i] == "era" then era = date_part end
	end
	return dd, mmmm, yyyy, era
end -- function p.date_split(date, format)

-- Extract a part of date following a pre-defined format which starts with separator
function p.date_to_part(date, part)
	-- local t, err = p.date_to_part(a.birthyear, " dd mmmm yyyy", "yyyy")
	part = part or "yyyy"
	local dd, mmmm, yyyy, era
	local found = false
	--	local err = "date_to_part_err_not_found"
	if not found then
		dd, mmmm, yyyy, era = p.date_split(date, "dd mmmm yyyy")
		if dd and mmmm and yyyy and not era then
			found = true
		end
	end
	if not found then
		dd, mmmm, yyyy, era = p.date_split(date, "mmmm dd yyyy")
		if dd and mmmm and yyyy and not era then
			found = true
		end
	end
	if not found then
		dd, mmmm, yyyy, era = p.date_split(date, "yyyy era")
		if not dd and not mmmm and yyyy then
			if era == "BCE" then yyyy = - yyyy end
			found = true
		end
	end
	if not found then
		dd, mmmm, yyyy, era = p.date_split(date, "mmmm yyyy")
		if not dd and mmmm and yyyy and not era then
			--	date_months_names				= "January, February, March, April, May, June, July, August, September, October, November, December",
			--	date_months_names				= "Enero, Febrero, Marzo, Abril, Mayo, Junio​​, Julio, Agosto, Septiembre, Octubre, Noviembre, Diciembre",
			--	date_months_names				= "Janvier, Février, Mars, Avril, Mai, Juin, Juillet, Août, Septembre, Octobre, Novembre, Décembre",
			found = true
		end
	end
	if not found then
		dd, mmmm, yyyy, era = p.date_split(date, "yyyy")
		if not dd and not mmmm and yyyy and not era then
			found = true
		end
	end
	-- + cccc = roman number ?
	if found then
		if part == "yyyy" then return yyyy or "" end
		if part == "mmmm" then return mmmm or "" end
		if part == "dd" then return dd or "" end
		if part == "era" then return era or "" end
	end
	return "" -- tostring(dd)..tostring(mmmm)..tostring(yyyy)..tostring(era)
--	A faire : Titus Livius (Q2039), format de dates : P569 = date of birth = 59 BCE, P570 = date of death = 17
--  Socrate (470-399 av. J.-C.).
end -- function p.date_to_part(date, part)

function p.i18n_lister(t, i18n_tables)
	if type(i18n_tables) ~= "table" then i18n_tables = CA.i18n end
	t = t or "\n* '''i18n_lister''' :"
	t = t .. CA.error_color("\n* '''This list show all the texts, but cannot replace the original declarations.''' ")
	t = t .. CA.error_color("\n* '''" .. CA.str_vars("i18n_list_all_texts") .. " ''' " )
	for lang, lang_table in pairs(i18n_tables) do
		t = t .. "\np.i18n." .. lang .. ' = { '
		if type(lang_table) == "table" then
			for key, text in pairs(lang_table) do
				if key and text then
					t = t .. "\n:" .. key .. ' = "' .. text .. '",'
				end
			end
		end
		t = t .. "\n}\n"
	end
	return t
end -- function p.i18n_lister(t, i18n_tables)

function p.date_to_part_test_1(t, nom, date, part)
	t = t .. CA.Tr() .. CA.Td(nom) .. CA.Td(date) .. CA.Td(part) .. CA.Td(tostring(CA.date_to_part(date, part)))
	return t
end

function p.date_to_part_test(t)
	t = t or "\n* '''date_to_part''' :"
	t = t .. "\n* Verify each value of part of date: Vérifier chaque valeur de partie de date :"
	t = t .. CA.Th() .. CA.Tc("Exemple") .. CA.Tc("date") .. CA.Tc("partie") .. CA.Tc("valeur")
	t = CA.date_to_part_test_1(t, "Socrate nais.", "470 BCE", "era")
	t = CA.date_to_part_test_1(t, "Tite-Live nais.", "59 BCE", "yyyy")
	t = CA.date_to_part_test_1(t, "Tite-Live mort.", "17", "yyyy")
	t = CA.date_to_part_test_1(t, "vide", "", "yyyy")
	t = CA.date_to_part_test_1(t, "Révolution", "14 juillet 1789", "mmmm")
	t = CA.date_to_part_test_1(t, "Marche sur la Lune", "20 juillet 1969", " ")
	t = CA.date_to_part_test_1(t, "English date", "July 20 1969", "yyyy")
	t = CA.date_to_part_test_1(t, "English date", "July 20 1969", "mmmm")
	t = CA.date_to_part_test_1(t, "Nelson Mandela nais.", "juillet 1918", "yyyy")
	t = CA.date_to_part_test_1(t, "Nelson Mandela décès", "5 décembre 2013", "dd")
	t = t .. CA.Te()
	return t
end -- function p.date_to_part_test(t)

function p.wikidata_test(t)
	local t = t or "\n* '''wikidata_test''' :"
	local wd, tw, wd_mng
	wd, tw, wd_mng = p.import_wikidata( p.args_known, "Q899264") -- Q899264#sitelinks = Martin Fleischmann
	t = t .. tw
	wd, tw, wd_mng = p.import_wikidata( p.args_known, "Q535") -- Q535 = Victor Hugo = Victor Marie Hugo
	t = t .. tw
	wd, tw, wd_mng = p.import_wikidata( p.args_known )
	if wd_mng and wd_mng.wd_entity and wd_mng.wd_entity.id then
		t = t .. "\n* Entity.id: " .. (wd_mng.wd_entity.id or "") -- entityid
		local structured_data_txt = CA.str_vars("structured_data_txt")
		t = t .. ' <span style="color:#232388; font-size:140%; line-height:120%; ">⦁&nbsp;&nbsp;</span>[[d:' .. wd_mng.wd_entity.id .. '|' .. structured_data_txt .. ']]<br/>'
	end
	t = t .. "\n* Asked properties: " .. tw
	t = t .. "\n* Properties maxn: " .. (wd_mng.props_maxn or "")
--	t = t .. "\n* Properties txt: " .. (wd_mng.props_txt or "")
	t = t .. "\n* Properties list: " .. (wd_mng.props_list or "")
	return t
end -- function p.wikidata_test(t)

function p.verify_args_tables(_known, _source)
	-- initialize all the values to "" in arg table
	-- p.init_args(args_known, p.args_source, "fr")
	if type(_known) == "table" then
		CA.args_known = _known
	end
	if type(CA.args_known) ~= "table" then
		p.err_add("err_no_known_arguments")
		p.cat_add("cat_no_known_arguments")
		return CA.error_color(" Internal error : no source or no known arguments ! ")
	end
	if type(_source) == "table" then
		CA.args_source = _source
	end
	if type(p.args_source) ~= "table" then
		CA.err_add("err_no_source_arguments")
		CA.cat_add("cat_no_source_arguments")
		return CA.error_color(" Internal error : no source or no known arguments ! ")
	end
	return
end -- function p.verify_args_tables(_known, _source)

function p.init_args(args_known, args_source, _user_lang, _msgs_list, _wiki_lang, _wiki_translations)
	-- p.init_args(args_known, p.args_source, "fr")
	p.init_spaces()
	--
	if type(args_known) ~= "table" then args_known = p.args_known end
	if type(args_known) ~= "table" then args_known = p.args_known_default end
	if type(args_known) == "table" then p.args_known = args_known end
	--
	if type(args_source) ~= "table" then args_source = p.args_source end
	if type(args_source) ~= "table" then args_source = p.args_source_example end
	if type(args_source) == "table" then p.args_source = args_source end
	--
	local err = CA.verify_args_tables(args_known, args_source)
	if err then return err end
	--
	-- langues du wiki par defaut
	if type(_wiki_lang) ~= "string" then -- langue pour args et categories
		_wiki_lang = mw.language.getContentLanguage().code
	end
	if type(_user_lang) ~= "string" then -- langue pour les erreurs et messages
		_user_lang = mw.language.getContentLanguage().code
	end
	--
	-- Si une langue est demandée sans sa table, utiliser la table déjà connue
	if type(_msgs_list) ~= "table" and type(_user_lang) == "string" and type(p.i18n[_user_lang]) == "table" then
		p.user_lang = _user_lang -- langue pour les erreurs et messages
	end
	if type(_wiki_translations) ~= "table" and type(_wiki_lang) == "string" and type(p.i18n[_wiki_lang]) == "table" then
		p.wiki_lang = _wiki_lang -- langue pour args et categories
	end
	-- Si une langue et sa table sont définies, la créer ou la remplacer parmi les autres
	if type(_msgs_list) == "table" and type(_user_lang) == "string" then
		p.i18n[_user_lang] = _msgs_list
		p.user_lang = _user_lang
	end
	if type(_wiki_translations) == "table" and type(_wiki_lang) == "string" then
		p.i18n[_wiki_lang] = _wiki_translations
		p.wiki_lang = _wiki_lang
	end
	--
	-- If the language or its table misses, show it by error and category
	-- Si la langue ou sa table manque, le signaler par erreur et par catégorie
	if type(p.wiki_lang) ~= "string" or type(CA.wiki_translations) ~= "table" then
		p.err_add("err_lang_table", p.user_lang)
		local err_lang_table_cat = p.cat_add("err_lang_table_cat")
	end
	--
	-- Limite de differences des arguments proposables à l'utilisateur
	p.max_nearest_argument = tonumber( p.i18n[p.wiki_lang]["max_nearest_argument"] ) or 3
	--
--	p.erron = true -- Errors actived or no. Errores activo o no. Erreurs activées ou non.
--	p.errors_list = {} -- initialise la collecte des erreurs
	return p.args_known, p.args_source, p.user_lang, p.i18n[p.wiki_lang], p.i18n
end -- function p.init_args(args_known, args_source, _user_lang, _msgs_list, _wiki_lang, _wiki_translations)

-- Processus global des arguments :
-- args = frame...
-- args_known = p.args_known
-- CA.wiki_translations = i18n.wiki_lang
-- wd = wikidata
-- import_args en 2 boucles : 1 Importer des args normaux
-- import_args en 2 boucles : 2 Traiter les anomalies apres wikidata et import
-- interact args
-- utilisation normale
-- tests unitaires

function CA.import_arguments(args_known, args_source, wiki_translations, args_wikidata)
	--	import all arguments from template, or wikidata
	local args_import = {} -- table d'arguments internationale simple
	local err = nil
	local cats = ""
	-- entrees alternatives et erreurs
	if type(args_known) ~= "table" then args_known = CA.args_known end
	if type(args_known) ~= "table" then args_known = CA.args_known_default end
	if type(args_source) ~= "table" then args_source = CA.args_source end
	if type(wiki_translations) ~= "table" then wiki_translations = CA.wiki_translations end
	if type(args_wikidata) ~= "table" then args_wikidata = CA.args_wikidata end
	CA.import_arguments_err = ""
	CA.import_arguments_track = ""
	local err = CA.verify_args_tables(args_known, args_source)
	if err then return args_import, err end
	--
	local err, er1, t2 = "", "", ""
	local key, argval, argid = "kkk", "xxx", ""
	local argknw, arglingual, argreceived = nil, "", ""
--	local trouve1, min1, trouve2, min2 = nil, 999, nil, 999
	local argm = {} -- argument usuel
--	CA.erron = true -- Errors actived or no. Errores activo o no. Erreurs activées ou non.
--	CA.errors_list = {} -- collecte de toutes les erreurs
	local key_N, key_NN = 0, 0
	local arg_found, rec_found, already_found = false, false, false
	--
	for key_known, argm in pairs(args_known) do
		argm.found = 0 -- Initialiser d'abord tous les arguments connus
	end
	--
	CA.args_unknown = mw.clone(CA.args_source) -- unknown arguments are source arguments without known arguments.
	-- Traiter tous les arguments connus
	local key_known_init = nil
--	local argm_orig = nil
	local argm_syn = nil
	for key_known, argm in pairs(args_known) do
		argm.src = nil
		argm.trk = " n"
		key_known_init = key_known
		-- Initialiser d'abord chaque argument connu
		CA.import_arguments_track = tostring(CA.import_arguments_track) .. " - " .. tostring(key_known)
		--
--		argm_orig = nil
		argm_syn = args_known[argm.keyword]
		if argm.syn == 1 then
			-- Pour les arguments non nommés, les nommer par leur synonyme
			-- Renommer les arguments nommés, par leur synonyme
--			argm_orig = key_known
			key_known = argm.keyword
			argm = args_known[key_known] -- new variable argm
			argm.src = nil
			argm.trk = "s"
			CA.import_arguments_track = tostring(CA.import_arguments_track) .. ">" .. tostring(key_known)
		end
		-- initialiser un argument
		arg_found = false
		argval = nil
		argm.trk = argm.trk.."="
		-- importer un argument wikidata
		if args_wikidata[key_known] then
			argval = args_wikidata[key_known]
			argm.src = "wd"
			argm.trk = argm.trk.."w"
			if argm_orig then
			--	args_known[argm_orig].src = "wd"
			--	args_known[argm_orig].trk = (args_known[argm_orig].trk or "").."w"
			end
--			if argm_orig then argm_orig = key_known end
			arg_found = true
			CA.import_arguments_track = CA.import_arguments_track .. "='''" .. tostring(argval) .. "''' "
		end
		-- importer un argument source
		arglingual = wiki_translations[key_known]
		CA.import_arguments_track = CA.import_arguments_track .. "/" .. tostring(arglingual)
		if arglingual then
			if args_source[arglingual] then
				argval = args_source[arglingual]
				argm.src = "args"
				argm.trk = argm.trk.." a"
				arg_found = true
				local arg_values = wiki_translations[argm.arg_values]
				if argm.keys_values and arg_values then
					-- The argument is limited to multiple values with arg_values and keys_values, and the values are defined.
					local pos = string.find(arg_values, argval)
					if pos then
						-- The value of the argument is in the multiple values of the arguments.
				--		argm.src = "args"
						argm.trk = argm.trk.."m"
				--		arg_found = true
						if argm_orig then
						--	args_known[argm_orig].src = "args"
						--	args_known[argm_orig].trk = (args_known[argm_orig].trk or "").."d"
						end
					else
						CA.err_add("args_values_err", argm.keyword, argval, arg_values)
				--		argval = nil
					end
				else
				--	argm.src = "args"
					argm.trk = argm.trk.."c"
				--	arg_found = true
					if argm_orig then
					--	args_known[argm_orig].src = "args"
					--	args_known[argm_orig].trk = (args_known[argm_orig].trk or "").."c"
					end
				end
				CA.import_arguments_track = CA.import_arguments_track .. "='''" .. tostring(argval) .. "''' "
			end -- not args_source[arglingual] is normal
		else -- internal error and category
			CA.err_add("err_module_miss_i18n", key_known)
			-- Generate a category to list all modules with missing translation
			cats = cats .. CA.cat_add( "err_module_miss_i18n_cat" )
		end
		--
		key_N = tonumber(key_known_init)
		if key_N and not args_known[key_N] then
--			CA.err_add("err_too_unnamed_arguments", key_N, argval)
		end
		-- Record the argument. Guarde el argumento. Enregistrer l'argument.
		if arg_found == true then
			argm.found = argm.found + 1 -- compter les arguments redéfinis
			argm.val = argval
			args_import[key_known] = argval -- table d'arguments internationale simple
			if CA.args_unknown[arglingual] then
				CA.args_unknown[arglingual] = nil -- unknown arguments are source arguments without known arguments.
			end
		end
	end
	--
	for key_known, argm in pairs(args_known) do -- For all known arguments
		-- Redefined arguments. Argumentos redefinieron. Arguments redéfinis.
		if argm.found and (argm.found > 1) then
			CA.err_add("err_value_re_defined", argm["keyword"])
			cats = cats .. CA.cat_add("cat_usage_error")
		end
		-- need = 0 not necessary argument
		-- need = 1 necessary from argument
		-- need = 2 necessary from argument or module interaction
		-- Missing Arguments. Argumentos que faltan. Arguments manquants.
		if argm.need and (argm.need == 1) and (not argm.val) then
			arglingual = wiki_translations[key_known]
			if arglingual then
				CA.err_add("err_need_value", arglingual)
				cats = cats .. CA.cat_add("cat_usage_error")
			end
		end
	end
	--
	-- Tous les arguments sources ont-ils été utilisés ?
	--	CA.args_unknown -- unknown arguments are source arguments without known arguments.
	local args_list = p.similar_args_list(CA.args_known)
	for key_src, val_src in pairs(CA.args_unknown) do -- For all unknown source arguments.
		arglingual = tostring(key_src) -- chercher l'argument traduit
		key_N = tonumber(arglingual)
		-- No error for unmamed arguments
		-- Pas d'erreur pour les arguments non nommés
		if not key_N then
			p.err_add("err_unknown_argument", arglingual, val_src)
			cats = cats .. p.cat_add("cat_usage_error")
			-- "Erreur : Le paramètre '''%1''' est inconnu dans ce modèle. Vérifier ce nom ou signaler ce manque.",
			-- Cherche un argument connu et de nom ressemblant
			local diffmaxi = p.similar_args_diffmaxi( string.len(arglingual) )
			local trouve1, min1, trouve2, min2 = p.similar_args_search(arglingual, args_list)
			if min1 and (min1 <= diffmaxi) then
				p.err_add("err_nearest_argument", trouve1)
			end
			if min2 and (min2 <= diffmaxi) then
				p.err_add("err_nearest_argument", trouve2)
			end
		end
		key_N = tonumber(arglingual)
		if key_N and not args_known[key_N] then
			CA.err_add("err_too_unnamed_arguments", key_N, val_src)
			p.cat_add("cat_usage_error")
		end
	end -- For all unknown source arguments.
	CA.nowyear = tonumber(os.date("%Y") ) -- local now_date = os.date("%Y-%m-%d %H:%M:%S")
	args_import.nowyear = CA.nowyear
	CA.args_import = args_import
	return CA.args_import
end -- function CA.import_arguments(args_known, args_source, wiki_translations, args_wikidata)

------------------------------------------------------------
-- Argts : Generate documentation. Generar documentación. Générer la documentation.
------------------------------------------------------------

function p.generDoc1(paramName, n, paramData, opt)
	-- t = t .. generDoc1("nom", "ws-name", "docline docdef")
	-- Normaliser les parametres et signaler les erreurs
	-- Toujours afficher quelque chose dans la documentation du module ou du modèle.
	if type(paramName) ~= "string" or type(paramData) ~= "string" then -- signaler l'erreur
		p.err_add("err_generDoc1_paramName", tostring(paramName) )
		return " "
	end
	opt = " "..tostring(opt).." " -- transparent, sinon peut donner nil, non génant
	--
	-- former le texte à afficher
	local newline = "<br/>"
	-- Chaque parametre non nommé est traité par son synonyme.
	if n then return "" end
	if p.option("docline", opt) then newline = "" end
	local argm = p.args_known[paramName]
	if argm then
		--[ [
		if p.option("docolor", opt) then --	Document the data sources by colors
			if argm.src == "wd" then
				paramData = p.wikidata_color(paramData)
			elseif argm.src == "args" then
				paramData = p.invoke_color(paramData)
		--	elseif argm.src == "inter" then
		--		paramData = p.inter_color(paramData)
			else
				paramData = p.other_color(paramData)
			end
		end
		--] ]
		paramData = paramData -- .. (argm.trk or "")
	end
	return " | " .. paramName .. " = <b>" .. paramData .. "</b>" .. newline
end -- function p.generDoc1(paramName, paramId, opt)

function p.generDoc(opt, args_final, module_name)
	-- Lister des paramètres pour la documentation du module
	-- "docview" ajouter le panneau de documentation
	-- "docmin" quelques paramètres de base
	-- "docdef" seulement les paramètres définis, ayant une valeur non nulle
	-- "docmax" tous les paramètres connus
	-- "docnotice" generer les documentations des notices
	-- "docline" mettre tous les paramètres sur une seule ligne
	-- "docsrc" mettre les paramètres en couleurs selon les sources
	-- p.options = " : docdata docmin docdef docmax docline docview docafter docnotice docsrc" -- for documentation
	-- p.options = " erron noerr nobox nocat " -- without normal result
	-- p.options = " debug tests en es fr " -- for debug or enforce language
	local args_known = CA.args_known
	local err = CA.verify_args_tables(args_known, CA.args_source)
	if err then return args_import, err end
	if type(module_name) ~= "string" then module_name = p.module_name end
	if type(module_name) ~= "string" then module_name = p.frame:getTitle() end -- main module, example "Auteur"
	if type(module_name) ~= "string" then module_name = "ControlArgs" end
	local n, t, val = 0, "", ""
	if type(args_final) ~= "table" then t = t.."err_args_final="..type(args_final).."<br/>" end -- optional arguments
	if type(args_final) ~= "table" then args_final = p.args_final end -- optional arguments
	local key, argknw, argval, arglingual = "", "", ""
	local lst = true
	for key, parm in pairs(args_final) do -- Pour tous les parametres connus
		val = ""
		n = tonumber(key)
		if n == nil then -- args en ordre numerique et renvoi vers un argument nommé
		--	n = 0
		else
			key = tostring(parm["keyword"])
		end
		argknw = args_known[key]
		arglingual = tostring(CA.user_translations[key]) -- multilingual name of the arg in the template
		if arglingual == "nil" then arglingual = key end -- reperer l'erreur si besoin, err_generDoc
		val = parm -- tostring(args_import[key])
		if not p.isDef(val) then val = "" end
		lst = false
		opt = opt .. " docdef "
		if p.option("docmin", opt) and (argknw["list"] == 1) then lst = true end
		if p.option("docdef", opt) and (val ~= "") then lst = true end
		if p.option("docmax", opt) then lst = true end
		if lst then -- lister arg si autorisé
			t = t .. p.generDoc1(arglingual, n, val, opt)
		end
	end
	t = "\n{{" .. module_name .. " " .. t .. "}}" -- <br/>
	return t
end -- function p.generDoc(opt, args_final, module_name)

------------------------------------------------------------
-- Running internal tests and their documentations.
-- Ejecución de las pruebas internas y su documentación.
-- Exécution des tests internes et de leurs documentations.
------------------------------------------------------------

local args_test_errors = { "aaa", "bbb", "ccc", "ddd", ["prénom"] = "Arthur",
	options = ' docdef docview docsrc ', lastXXname = 'Voltaire', birthyear = '1999', birthyear = '2000',
} -- Arguments pour auto-test

-- Interact parameters in international args_final
function p.interact_args_final(args_final)
	-- args_final = p.interact_args_final(args_import)
	if type(args_final) ~= "table" then args_final = CA.args_final end
	if type(args_final) ~= "table" then args_final = CA.args_import end
	local a = args_final
	local i = {} -- interact
	t = t .. "\n* begin :" .. CA.ta("initiale", a.initiale) .. CA.ta("firstname", a.firstname) .. CA.ta("lastname", a.lastname) .. CA.ta("title", a.title)
	--
	local tit = nil
	if not a.title then -- If title is undefined, enforce it.
		if a.lastname and a.firstname then
			tit = a.firstname .. " " .. a.lastname
		end
		i.title = a.label or tit or a.sitelink or a.lastname or CA.module_name
	end
	--
	if not a.initiale then -- If initiale is undefined, enforce it.
		-- if absent, default initiale come from the last word of title
		local title = a.title or i.title
		if title then
			local tab = mw.text.split(title, '%s') -- table of words
			local max = table.maxn( tab )
			i.initiale = tab[max] -- select the last word
			i.initiale = string.sub( i.initiale, 1, 1 ) -- select the first letter
			i.initiale = string.upper( i.initiale or "" )
		end
	end
	--
	-- if absent, synonym of basic arguments, syn = 1
	if not a.firstname then i.firstname = (i.firstname2 or a.firstname2) end
	if not a.lastname then i.lastname = (i.lastname2 or a.lastname2) end
	if not a.firstname2 then i.firstname2 = (i.firstname or a.firstname) end
	if not a.lastname2 then i.lastname2 = (i.lastname or a.lastname) end
	--
	if a.birth and not a.birthyear then
		local tt, err = p.date_to_part(a.birth, CA.str_vars("date_to_part_format"), "yyyy")
		if tt then i.birthyear = tt else
			CA.err_add(err, CA.str_vars("birthyear"), "yyyy")
			CA.cat_add("date_to_part_call_cat")
		end
	end
	--
	-- memorize interactions in CA.args_final and show errors or messages
	local n = 0
	for key, val in pairs(i) do
		local args_kwn = CA.args_known[key]
		if args_kwn then
			args_final[key] = val -- = i[key]
			args_kwn.src = "inter"
			args_kwn.trk = args_kwn.trk.." i"
			n = n + 1
			if (args_kwn.need == 2) and not a[key] then --
				-- need=2 necessary from argument or module interaction
				CA.msg_add("msg_auto_val_warning", CA.user_translations[key], val)
			--	CA.msg_add("msg_automatic_argument", CA.user_translations[key], val)
			end
		else
			CA.err_add("msg_auto_val_unknown", CA.wiki_translations[key], val)
		--	CA.err_add("msg_unknown_auto_arg", CA.wiki_translations[key], val)
		end
	end
	if CA.args_known.title then CA.args_known.title.trk = (CA.args_known.title.trk or "").."i="..n end
	t = t .. "\n*: end :" .. CA.ta("initiale", a.initiale) .. CA.ta("firstname", a.firstname) .. CA.ta("lastname", a.lastname) .. CA.ta("title", a.title)
	CA.args_final = args_final
--	p.args_final = args_final
	return args_final, t
end -- function p.interact_args_final(args_final)

function p.table_compte(tab)
	if p[tab] == nil then return p.str_vars("Table '''%1''' nulle. ", tab) end
	if p[tab] == nil then return p.str_vars("Table '''%1''' vide. ", tab) end
	local st, vr, fn, tb = p.testable_lister(p[tab], "p."..tab)
	local t = p.str_vars("Table '''%1''' : comptes tabs='''%2''', vars='''%3''', funcs='''%4''' ", tab, tb, vr, fn)
	return t
end -- function p.table_compte(tab)

function p.tables_comptes(txt)
	local t = txt or "\n* Comptes des tables : "
	t = t .. "<br/>" .. p.table_compte("i18n")
	t = t .. "<br/>" .. p.table_compte("wiki_translations")
	t = t .. "<br/>" .. p.table_compte("user_translations")
	t = t .. "<br/>" .. p.table_compte("args_known")
	t = t .. "<br/>" .. p.table_compte("args_wikidata")
	t = t .. "<br/>" .. p.table_compte("args_source")
	t = t .. "<br/>" .. p.table_compte("args_unknown")
	t = t .. "<br/>" .. p.table_compte("args_import")
	t = t .. "<br/>" .. p.table_compte("args_final")
	t = t .. "<br/>" .. p.table_compte("errors_list")
	t = t .. "<br/>" .. p.table_compte("categories_list")
	return t
end -- function p.tables_comptes()

function p.debug_traceback(t)
	if type(t) ~= "string" then t = "\n* '''debug.traceback()''' : " end
	t = t .. debug.traceback()
	t = string.gsub(t, "Module", "\n* Module" )
	return t
end

function p.gener_tests_init(res, args_source)
-- Special init for the test mode
	if type(res) ~= "string" then res = "\n* Mode test : " end
	if type(args_source) ~= "table" then args_source = {} end
	--[[
	if p.i18n and p.i18n.en then p.i18n.es.error_i18n_wanted = 'EN error wanted' end
	if p.i18n and p.i18n.es then p.i18n.es.error_i18n_deseada = 'ES error deseada' end
	if p.i18n and p.i18n.fr then p.i18n.fr.error_i18n_voulue = 'FR erreur voulue' end]]
--[[
	if lang == "en" then args_source = p.ArgtestEN end
	if lang == "es" then args_source = p.ArgtestES end
	if lang == "fr" then args_source = p.ArgtestFR end
--]]
	if not args_source.name then args_source.name = "Jack Smith" end
	if not args_source.nom then args_source.nom = "Victor Hugo" end
	if not args_source.region then args_source.region = "india" end
	if not args_source["région"] then args_source["région"] = "chine" end
	if not args_source.description then args_source.description = "Victor Hugo est très connu." end
	if not args_source.genre then args_source.genre = "Romanciers,Poètes,Auteurs de théatre" end
	if not args_source.langue then args_source.langue = "français,japonais" end
	if not args_source.occupation then args_source.occupation = "Académiciens,Personnalités politiques" end
	p.args_source = args_source
	return res
end -- function p.gener_tests_init(res, args_source)

--	Documentations et tests détaillés supplémentaires
function p.gener_tests(args_final)
	if type(args_final) ~= "table" then args_final = CA.args_final end -- optional arguments
	local res = "\n:.\n"
	local content = ""
	-- CA.options = " : docdata docmin docdef docmax docline docsrc docview docafter docnotice docsrc" -- for documentation
	-- CA.options = " erron noerr nobox " -- without normal result
	-- CA.options = " debug tests en es fr " -- for debug or enforce language
--	CA.gener_tests_init(res, CA.args_source)
	--
	content = CA.used_options_list("\n* Options and their uses. Options et leur utilisation : ")
	res = res .. CA.dropdown_box(1, "Options and their uses. Options et leur utilisation", content, nil, "===")
	--
	content = CA.tables_comptes("\n* Comptages des contenus de tables : ")
	res = res .. CA.dropdown_box(1, "Comptages des contenus de tables", content, nil, "===")
	--
	content = CA.search_namespace("\n* Module, namespaces, and page names")
	res = res .. CA.dropdown_box(1, "Module, namespaces, and page names", content, nil, "===")
	--
	content = CA.wikidata_test("\n\n* Tests et données importées de '''wikidata''' : ")
	res = res .. CA.dropdown_box(1, "Tests et données importées de wikidata.", content, nil, "===")
	
	res = res .. p.dropdown_func(1, "Tests date vers jour, mois, année ou ère", CA.date_to_part_test)

	--
	content = CA.cat_add_test( "\n\n* Test des catégories générées par '''cat_add''' :" )
	res = res .. CA.dropdown_box(1, "Tests unitaires des catégories", content, nil, "===")
	--
	content = CA.levenshtein_test( "\n\n* Test des distances entre mots de '''levenshtein''' : ", c)
	res = res .. CA.dropdown_box(1, "Test des distances entre mots de '''[https://fr.wikipedia.org/wiki/Distance_de_Levenshtein levenshtein]'''", content, nil, "===")
	--
	content = CA.similar_args_test( "\n\n* Test des mots proches similar_args : ", c)
	res = res .. CA.dropdown_box(1, "Test des mots proches similar_args", content, nil, "===")
	--
	content = CA.testable_lister(CA.tablim, "CA.tablim", {} )
	res = res .. CA.dropdown_box(1, "Liste de table, test sans limites", content, nil, "===")
	--
	content = CA.testable_lister(CA.tablim, "CA.tablim", { levelmaxi = 2, max_n = 2, exclude1 = "hou" } )
	res = res .. CA.dropdown_box(1, "Liste de table, test avec limites", content, nil, "===")
	--
	content = CA.testable_lister(CA.args_source, "CA.args_source")
	-- content = content .. "\n:.\n* import_arguments_track : " .. CA.import_arguments_track
	res = res .. CA.dropdown_box(1, "Détails  des arguments reçus", content, nil, "===")
	--
	content = CA.testable_lister(CA.args_unknown, "CA.args_unknown")
	res = res .. CA.dropdown_box(1, "Détails des arguments inconnus, args_unknown", content, nil, "===")
	--
	content = CA.testable_lister(CA.args_known, "CA.args_known")
	res = res .. CA.dropdown_box(1, "Détails des arguments connus : args_known", content, nil, "===")
	--
	content = CA.verif_i18n(CA.i18n)
	res = res .. CA.dropdown_box(1, "Translations missing, Manques de traductions : i18n", content, nil, "===")
	--
--	content = CA.testable_lister(CA.i18n, "CA.i18n")
--	res = res .. CA.dropdown_box(1, "Translations. Détails des tables de traductions : i18n", content, nil, "===")
	
	res = res .. p.dropdown_func(1, "Combined i18n translations tables. Tables de traductions i18n combinées.", CA.i18n_lister)
	--
	content = CA.dummy_languages() or "dummy_languages is empty"
	res = res .. CA.dropdown_box(1, "Dummy languages. Langues plus ou moins bien définies", content, nil, "===")
	--
	--[[
	local t = {} ; t[1] = "n1" ; t[2] = "n2" ; t["1"] = "s1" ; t["2"] = "s2" ;
	t.a = "A" ; t.b = "B" ; t[3] = "n3" ; t.c = "C"
	res = res .. "\n*-- ipairs : "
	for k, v in ipairs(t) do res = res .. ", " .. tostring(k) .. "=" .. tostring(v) end
	res = res .. "\n*-- pairs : "
	for k, v in pairs(t) do res = res .. ", " .. tostring(k) .. "=" .. tostring(v) end
	res = res .. "\n*-- next : "
	for k, v in next, t do res = res .. ", " .. tostring(k) .. "=" .. tostring(v) end
	-- result give : ipairs : , 1, n1, 2, n2, 3, n3 -- pairs : , 1, n1, 2, n2, 3, n3, 1, s1, c, C, 2, s2, a, A, b, B -- next : , 1, n1, 2, n2, 3, n3, 1, s1, c, C, 2, s2, a, A, b, B ,
	-- ]]
	return res
end -- function p.gener_tests(args_final)

function CA.sources_of_datas_colors()
	local res = ""
	if CA.option("docolor") then --	Document the data sources by colors
		local sources_of_datas = CA.str_vars("sources_of_datas")
		--	sources_of_datas = "Informations from: /Wikidata, /template or module, /other, /message, /error",
		local splitxt = mw.text.split(sources_of_datas, "/", true)
		res = res .. splitxt[1]  .. " ''' " .. CA.wikidata_color(splitxt[2]) .. CA.invoke_color(splitxt[3]) .. CA.other_color(splitxt[4]) .. CA.message_color(splitxt[5]) .. CA.error_color(splitxt[6]) .. ".''' <br/>"
	else --	Document the data sources in black on white
--		local sources_of_datas = CA.str_vars("sources_of_datas")
--		res = res .. string.gsub(sources_of_datas, "/", "") .. ".''' <br/>"
	end
	return res
end -- function CA.sources_of_datas_colors()

-- Display the documentation in an infobox, similar to edit-boxs
-- Affichage de documentation dans un cadre (box), semblable aux boites d'edition
function p.generDocBox(args_final)
	-- p.options = " : docdata docmin docdef docmax docline docsrc docview docafter docnotice docsrc" -- for documentation
	-- p.options = " erron noerr nobox " -- without normal result
	-- p.options = " debug tests en es fr " -- for debug or enforce language
	if type(args_final) ~= "table" then args_final = CA.args_final end -- optional arguments
	local err = CA.verify_args_tables(CA.args_known, CA.args_source)
	if err then return err end
	local res = CA.str_vars("err_delete_docbox")
	res = CA.error_color("<center><b>" .. res .. "</b><br/></center>")
	if CA.option("docolor") then --	Document the data sources by colors
		res = res .. "\n:.\n: " .. CA.sources_of_datas_colors()
	end
	if p.option("debug") then
		res = res .. "\n* " .. p.ta("p.catView", p.catView) .. p.ta("p.invoke_options", p.invoke_options) .. p.ta("p.mode_options", p.mode_options)
	end
	if type(CA.args_wikidata) == "table" and p.option("docdata") then
		res = res .. "\n* " .. p.generDoc(" docdef docline ", CA.args_wikidata, "Wikidata")
	end
	if type(args_final) == "table" and p.option("docview") then
		res = res .. "\n* " .. p.generDoc(" ", args_final, "ControlArgs")
	end
	if not p.option("noerr") then res = res .. "\n* " .. p.errors_lister() end
	res = res .. "\n* " .. CA.categories_lister(":")
	res = '<div style=" width=90%; border: 1px solid #AAAAAA; margin:1em; background-color:#F1F1F1; padding:0.3em; ">' .. res .. '</div>\n\n'
	return res
end -- function p.generDocBox(args_final)

function CA.tatrk(key, val, trk)
	local res = ""
	res = res .. CA.ta(key, val)
	if (trk or CA.trkView) and CA.args_known[key] then res = res .. (CA.args_known[key].trk or "") end
	return res
end -- function CA.tatrk(key, val, trk)

function p.normal_box(args_final, title)
	local res = ""
	if type(args_final) ~= "table" then args_final = p.args_final end
	if not title then title = args_final.title end
	if not title then title = "TITLE" end
	res = res .. "<center><b><big>" .. title .. "</big></b><br/></center>"
	res = res .. "L'auteur	'''" .. tostring(args_final.firstname) .. " " .. tostring(args_final.lastname) .. "''' "
	res = res .. " est mort en '''" .. tostring(args_final.deathyear) .. "'''"
	res = res .. " et son image est '''" .. tostring(args_final.image) .. "'''.<br/>"
	res = res .. CA.tatrk("initiale", args_final.initiale)
	res = res .. CA.tatrk("firstname", args_final.firstname)
	res = res .. CA.tatrk("lastname", args_final.lastname)
	res = res .. CA.tatrk("title", args_final.title)
	res = res .. CA.tatrk("region", args_final.region)
	res = res .. CA.tatrk("rights", args_final.rights)
	res = res .. CA.tatrk("language", args_final.language)
--	CA.catGroup("language_cat", args_final.language) -- |language=french,italian,chinese
--	CA.catGroup("occupation_cat", args_final.language) -- |occupation=Académiciens,Personnalités politiques
	res = res .. CA.catGroup("language_cat", args_final.language) -- |language=french,italian,chinese
	res = res .. CA.catGroup("occupation_cat", args_final.occupation) -- |occupation=Académiciens,Personnalités politiques
	CA.catGroup("genre_cat", args_final.genre) -- |genre=Romanciers,Poètes,Auteurs de théatre
	if CA.trkView then -- debug trak .trk of sources of arguments .src
		res = res .. CA.categorizer()
	end
	CA.trkView = true
	res = '<div style="margin-right:5px; box-shadow:0.2em 0.3em 0.2em #B7B7B7; background-color:#F1F1DE; padding:0.3em; width=90%; overflow-x:hidden; ">' .. res .. '</div>'
	return res
end -- function p.normal_box(args_final, title)

-- Normal result of the module
function p.gener_result(args_final)
	if type(args_final) ~= "table" then args_final = p.args_final end -- optional arguments
	local res, normal = " ", " "
	if not p.option("nobox")	then normal = p.normal_box(args_final, nil) end
	if p.option("docview")		then res = res .. p.generDocBox(args_final) end
	res = res .. normal .. " "
--	res = res .. p.used_options_list("\n. '''gener_result''' : ")
	if not p.option("nocat") then res = res .. CA.categorizer() end
	return res
end -- function p.gener_result(args_final, lang)

-- Simulate the import of arguments from template, avec choix des langues du wiki et du user
-- Simuler l'import des arguments d'un modèle, avec choix des langues du wiki et du user
-- function p.import_lang(args_known, args_source, user_lang, wiki_lang, mode_options, title)
function p.import_lang(args_known, args_wikidata, args_source, user_lang, wiki_lang, mode_options, title)
	if type(args_known) ~= "table" then args_known = CA.args_known end -- optional arguments
	if type(args_wikidata) ~= "table" then args_wikidata = CA.args_wikidata end -- optional arguments
	local res = ""
	res = res .. "\n.\n<big><b>" .. title .. "</b></big> " .. CA.ta("user_lang", user_lang) .. CA.ta("wiki_lang", wiki_lang)
	CA.module_init()
	p.used_options = {}
	p.errors_list = {} -- collecte de toutes les erreurs et messages
	p.categories_init() -- initialize the category list
--	CA.invoke_options = ( CA.invoke_options or " " ) --.. " " .. user_lang
--	CA.mode_options = ( mode_options or " " ) --.. " " .. wiki_lang
	CA.init_user_lang(user_lang, wiki_lang) -- res = res ..
	if not CA.user_translations then return " - not CA.user_translations 1- " end
	p.init_args(args_known, args_source, wiki_lang, msgs_list)
	p.import_arguments( args_known, args_source, msgs_list, args_wikidata)
	CA.invoke_options = args_source.c or ""
	CA.mode_options = mode_options
	local args_final = p.interact_args_final(args_import)
	return res
end -- function p.import_lang(args_known, args_source, lang, options, title)

function p.tests_langs(args_known)
	local res = ""
	res = res .. "\n.\n* '''Tests in a few languages. Tests en quelques langues. Pruebas en unos pocos idiomas. ''' :"
	--
	res = res .. p.import_lang(args_known, p.WikidataEN, CA.ArgtestFR, "en", "fr", "  docview docline docsrc docolor ", " '''Test in english''' ")
--	res = res .. CA.tables_comptes("\n* langtest before gener_result '''en''' : ")
	res = res .. p.gener_result()
	--
	res = res .. p.import_lang(args_known, p.WikidataEN, CA.ArgtestFR, "es", "fr", "  docview docline docsrc docolor ", " '''Prueba en español''' ")
--	res = res .. CA.tables_comptes("\n* langtest before gener_result '''es''' : ")
	res = res .. p.gener_result()
	--
	res = res .. p.import_lang(args_known, p.WikidataEN, CA.ArgtestEN, "fr", "en", "  docview docline docsrc docolor ", " '''Test en français''' ")
--	res = res .. CA.tables_comptes("\n* langtest before gener_result '''fr''' : ")
	res = res .. p.gener_result()
	return res
end -- function p.tests_langs(args_known, args_source)

function p.tests_time( if_view, res, time1, time2, time3, time4)
	-- Display example :
	-- Execution and test time : 2014-02-22 18:09:15 UTC , url = http://fr.wikisource.org/wiki/Module:ControlArgs/Documentation ,
	-- start = 84 mS , import + 8 mS , generate page + 0 mS , tests + 127 mS , total = 221 mS ControlArgs:tests:fr
	if not if_view then return "" end
	time1 = time1 or p.time1
	time2 = time2 or p.time2
	time3 = time3 or p.time3
	time4 = time4 or p.time4
	local nowyear = os.date("%Y-%m-%d %H:%M:%S")
	local mwtitle = mw.title.getCurrentTitle()
	local url = tostring(mwtitle:canonicalUrl( ))
	local time2d = time2 - time1
	local time3d = time3 - time2
	local time4d = time4 - time3
	local total = time4
	time1  = tostring(math.floor( time1	 * 1000 )) .. " mS"
	time2d = tostring(math.floor( time2d * 1000 )) .. " mS"
	time3d = tostring(math.floor( time3d * 1000 )) .. " mS"
	time4d = tostring(math.floor( time4d * 1000 )) .. " mS"
	total = tostring(math.floor( total * 1000 )) .. " mS"
	res = res or ""
	res = res .."\n* Execution and test time : " .. nowyear .. " UTC" .. p.ta("url", url) -- <br/>
	res = res .. p.ta("<br/>start", time1) .. p.ta("import", time2d, "+")
	res = res .. p.ta("generate page", time3d, "+") .. p.ta("tests", time4d, "+") .. p.ta("total", total)
	return res
end -- function p.tests_time( if_view, res, time1, time2, time3, time4)

------------------------------------------------------------
-- Arguments sources exemples
------------------------------------------------------------

p.WikidataEN = { label = "John Smith", deathyear = "1789",  country = "France" }

p.ArgtestEN = { "mode One", "Rimbaud 2", name = "Rimbaud", firstname = "Arnaud", rights = "70", rights = "33", region = "Iowa", deathyear = "MDCCCJL",  image = "Carjat Arthur Rimbaud 1872 n2.jpg", langue = "allemand,français,espagnol", language = "french,italian,chinese" }

p.ArgtestES = { nombre = "Rimbaud", apellido = "Arthur", optionsES = " ", derechoss = "70", anoMuerte = "MDCCCJL",  imagen = "Carjat Arthur Rimbaud 1872 n2.jpg", idioma = "inglés,italiano,chino" }

p.ArgtestFR = { "mode Un", "Rimbaud 2", "Jonh", nom = "Smith", ["prénom"] = "Arnaud", droits = "70", anneeDeces = "1234", image = "Carjat Arthur Rimbaud 1872 n2.jpg", region = "Grèce", ["région"] = "ailleurs", langue = "allemand,français,espagnol", language = "french,italian,chinese" }

------------------------------------------------------------
-- Main interface to templates
-- Interfaz principales de modelos
-- Interface principal avec les modèles
------------------------------------------------------------

function CA.module_init()
--	Mix arguments from the template and the module.
	CA.args_source = CA.table_mixer(CA.frame.args, CA.frame:getParent().args)
	CA.categories_init()
	CA.init_user_lang()
	CA.verif_i18n()
	CA.init_args()
	return
end

function p.base(frame, function_mode, mode_options)
	p.time1 = os.clock()
	local res, t = "", ""
	p.frame = frame
	p.module_name = p.frame:getTitle() -- example "Module:Auteur"
	local lang = tostring(mw.language.getContentLanguage().code)
	-- import and count sources arguments in wiki language
	local args_invoke = frame.args
	local args_template = frame:getParent().args
	--
--	Add or replace all the arguments from the template inside arguments from the module.
--	Remplacer ou ajouter tous les champs du modèle dans ceux du module.
	local args_source, args_src_ni, args_src_nn = CA.table_mixer(args_invoke, args_template)
	CA.args_source = args_source
	--
	-- Initialize i18n languages tables, need to adapt in calling modules
	CA.add_i18n(CA.i18n_args)
	CA.add_i18n("Module:ControlArgs/I18N")
	CA.categories_init() -- initialize the category list
	CA.init_user_lang()
	CA.verif_i18n("Module:ControlArgs/I18N")
	if function_mode == "langtest" then
		CA.args_source = p.ArgtestEN
	end
--[[if function_mode == "doc" then
		p.args_known_default = nil
		CA.args_known = nil
		CA.args_source = nil
	end]]
	CA.init_args( p.args_known_default, CA.args_source, lang, msgs_list)
	--
	-- Import and adapt wikidata
	local args_wikidata, t = CA.import_wikidata(CA.args_known)
	local args_import, t = CA.import_arguments(p.args_known_default, CA.args_source ) -- , p.i18n.fr, args_source
	CA.args_import = args_import
	CA.invoke_options = args_source.c
	CA.mode_options = mode_options
	--
	-- Interactions between argumensts (title, initiale ...)
	-- Interactions entre parametres (titre, initiale ...)
	CA.args_final = p.interact_args_final(CA.args_import)
	--
	-- Mode from arguments
	CA.args_final.mode = args_template.mode or args_template[1] or args_template["1"]
	or args_invoke.mode or args_invoke[1] or args_invoke["1"]
	or function_mode or "normal"
	CA.mode_name = CA.args_final.mode
	CA.time2 = os.clock()
	--
	-- Options from mode
	if CA.mode_name == "normal" then
		mode_options = "noerr"
	elseif CA.mode_name == "doc" then
		mode_options = " : docdef docview docline docsrc" --	 docdata
--	elseif mode_name == "notice" then mode_options = "noerr"
--	elseif mode_name == "oldargs" then mode_options = "noerr"
	elseif CA.mode_name == "langtest" then
		mode_options = " : docdef docview docline docsrc docdata"
	elseif CA.mode_name == "tests" then
		mode_options = " : docdef docview docline docsrc docdata tests"
	end
	CA.mode_options = mode_options
	--
--	res = res .. "\n* " .. p.ta("p.import_arguments_track", p.import_arguments_track)
--	res = res .. "\n* mode " .. p.ta("CA.mode_name", CA.mode_name)
	--
	local res_function = "\n" .. CA.module_name .. ":" .. CA.mode_name .. ":" .. CA.wiki_lang .. " "
	if CA.mode_name == "doc" or CA.mode_name == "tests" then
		res = res .. "<br/>" .. res_function
	end
	--
	if CA.mode_name == "langtest" then
		-- Detailed tests depends from options
		res = res .. p.tests_langs(args_known, args_source)
	elseif CA.mode_name == "tests" then
		-- Generate normal wikitext, categories, and others
		res = res .. p.gener_result(args_final, nil)
		-- Detailed tests depends from options
		res = res .. p.gener_tests(CA.args_final)
	else
		-- Generate normal wikitext, categories, and others
		res = res .. p.gener_result(args_final, nil)
	end
	p.time3 = os.clock()
	--
	if p.option("tests") then
		-- Detailed tests depends from options
		res = res .. p.gener_tests(CA.args_final)
	end
	p.time4 = os.clock()
--	res = res .. p.tables_comptes("\n* Comptages des tables '''base''' : ")
	--
	if CA.option("tests") or CA.option("docview") or CA.option("debug") then
		res = res .. CA.tests_time(true, "")
		res = res .. res_function
	end
	return res
end -- function p.base(frame, function_mode, mode_options)

------------------------------------------------------------
-- Interfaces, alias and functions to templates
-- Interfaces, alias y funciones para modelos
-- Interfaces, allias et fonctions pour les modèles
------------------------------------------------------------

function p.normal(frame)
--	return p.base(frame, "normal", "noerr")
	CA.trkView = false -- debug trak .trk of sources of arguments .src
	CA.time1 = os.clock()
	local res, t = "", ""
	CA.frame = frame
	CA.add_i18n(CA.i18n_args) -- Initialize i18n languages tables
	CA.add_i18n("ControlArgs/I18N")
	CA.module_init()
	CA.import_wikidata(CA.args_known)
	CA.args_wikidata = p.WikidataEN
	CA.import_arguments(p.args_known_default, CA.args_source )
	CA.invoke_options = CA.args_source.c
	CA.mode_options = "" -- : tests docview docline docsrc docdata docdef" -- noerr
	CA.mode_name = "normal"
	CA.args_final = p.interact_args_final(CA.args_import) -- Interactions between argumensts
	CA.time2 = os.clock()
	res = res .. p.gener_result() -- Generate normal wikitext, categories, and others
--	res = res .. CA.used_options_list("\n. '''normal''' : ")
	CA.time3 = os.clock()
	if CA.option("tests_langs") then
		res = res .. p.tests_langs()
		CA.time4 = os.clock()
		res = res .. CA.tests_time(true, "")
	elseif CA.option("tests") then
		res = res .. p.gener_tests()
		CA.time4 = os.clock()
		res = res .. CA.tests_time(true, "")
	end
	return res
end -- function p.normal(frame)

function p.doc(frame)
--	return p.base(frame, "doc", " : docdef docview docline docsrc")
	CA.trkView = true -- debug trak .trk of sources of arguments .src
	local res, t = "", ""
	CA.frame = frame
	CA.add_i18n(CA.i18n_args) -- Initialize i18n languages tables
	CA.add_i18n("ControlArgs/I18N")
	CA.module_init()
	CA.import_wikidata(CA.args_known)
	CA.args_wikidata = p.WikidataEN
	CA.args_wikidata = CA.authorities_select(CA.args_wikidata)
	CA.import_arguments(p.args_known_default, CA.args_source )
	CA.invoke_options = CA.args_source.c
	CA.mode_options = " : docdef docview docline docsrc docolor"
	p.interact_args_final(CA.args_import) -- Interactions between argumensts
	CA.mode_name = "doc"
	res = res .. p.gener_result() -- Generate normal wikitext, categories, and others
	return res
end -- function p.doc(frame)

function p.langtest(frame)
--	return p.base(frame, "langtest", " : docdef docview docline docsrc")
	CA.trkView = true -- debug trak .trk of sources of arguments .src
	CA.time1 = os.clock()
	local res, t = "", ""
	CA.frame = frame
	CA.add_i18n(CA.i18n_args) -- Initialize i18n languages tables
	CA.add_i18n("ControlArgs/I18N")
	CA.module_init()
	CA.args_source = p.ArgtestEN
	CA.import_wikidata(CA.args_known)
	CA.args_wikidata = p.WikidataEN
	CA.import_arguments(p.args_known_default, CA.args_source )
	CA.invoke_options = CA.args_source.c
	CA.mode_options = " : docdef docview docline docdata docsrc docolor"
	CA.args_final = p.interact_args_final(CA.args_import) -- Interactions between argumensts
	CA.mode_name = "langtest"
	CA.time2 = os.clock()
	res = res .. p.tests_langs(args_known, args_source)
	return res
end -- function p.langtest(frame)

function p.tests(frame)
	CA.trkView = true -- debug trak .trk of sources of arguments .src
	CA.time1 = os.clock()
	local res, t = "", ""
	CA.frame = frame
	CA.add_i18n(CA.i18n_args) -- Initialize i18n languages tables
	CA.add_i18n("ControlArgs/I18N")
--	CA.add_i18n("Module:ControlArgs/I18N")
	CA.module_init()
	CA.gener_tests_init(res, CA.args_source)
	CA.import_wikidata(CA.args_known)
	CA.args_wikidata = p.WikidataEN
	CA.import_arguments(p.args_known_default, CA.args_source )
	CA.invoke_options = CA.args_source.c
	CA.mode_options = " : tests docdata docdef docview docline docsrc docolor "
	CA.args_final = p.interact_args_final(CA.args_import) -- Interactions between argumensts
	CA.mode_name = "tests"
	CA.time2 = os.clock()
	local res_function = "<br/>\n" .. CA.module_name .. ":" .. CA.mode_name .. ":" .. CA.wiki_lang .. " "
	res = res .. res_function
	res = res .. p.gener_result() -- Generate normal wikitext, categories, and others
	CA.time3 = os.clock()
	res = res .. p.gener_tests()
--	res = res .. "\n* '''import_arguments_track''' : " .. p.import_arguments_track
	CA.time4 = os.clock()
	res = res .. CA.tests_time(true, "")
	res = res .. res_function
	return res
end -- function p.tests(frame)

return p