Ir al contenido

Módulo:scripts

De Wikcionario, el diccionario libre

La documentación para este módulo puede ser creada en Módulo:scripts/doc

--cf https://en.wiktionary.org/wiki/Módulo:scripts

local export = {}

local combining_classes_module = "Módulo:unicode-base/combinaciones"
local string_utilities_module = "Módulo:string"
local scripts_data_module = "Módulo:scripts/datos"

local require = require
local select = select
local setmetatable = setmetatable
local type = type

local insert = table.insert
local concat = table.concat

local match = string.match

local toNFC = mw.ustring.toNFC
local toNFD = mw.ustring.toNFD
local toNFKC = mw.ustring.toNFKC
local toNFKD = mw.ustring.toNFKD

local make_object -- Defined below.

--[==[
Loaders for functions in other modules, which overwrite themselves with the target function when called. This ensures modules are only loaded when needed, retains the speed/convenience of locally-declared pre-loaded functions, and has no overhead after the first call, since the target functions are called directly in any subsequent calls.]==]
local function split(...)
	split = require(string_utilities_module).split
	return split(...)
end

local function ugsub(...)
	ugsub = require(string_utilities_module).gsub
	return ugsub(...)
end

local function umatch(...)
	umatch = require(string_utilities_module).match
	return umatch(...)
end

local scripts_data
local function get_scripts_data()
	scripts_data, get_scripts_data = require(scripts_data_module), nil
	return scripts_data
end

local Script = {}
Script.__index = Script

--[==[Returns the script code of the language. Example: {{code|lua|"Cyrl"}} for Cyrillic.]==]
function Script:getCode()
	return self._code
end

--[==[Returns the canonical name of the script. This is the name used to represent that script on Wiktionary. Example: {{code|lua|"Cyrillic"}} for Cyrillic.]==]
function Script:getCanonicalName()
	return self._data[1]
end

--[==[Returns the display form of the script.]==]
function Script:getDisplayForm()
    local name = self._data[1]
    return "script "..name
end

function Script:getOtherNames()
	return self._data.otherNames
end

function Script:getAliases()
	return self._data.aliases or {}
end

function Script:getVarieties(flatten)
	return self._data.varieties or {}
end

function Script:getIETFSubtag()
	local code = self._ietf_subtag
	if code == nil then
		code = self._data.ietf_subtag or match(self:getCode(), "[^%-]+$")
		self._ietf_subtag = code
	end
	
	return code
end

--[==[Returns the parent of the script. Example: {{code|lua|"Latn"}} for {{code|lua|"Latnx"}} and {{code|lua|"Arab"}} for {{code|lua|"fa-Arab"}}. It returns {{code|lua|"top"}} for scripts without a parent, like {{code|lua|"Latn"}}, {{code|lua|"Grek"}}, etc.]==]
function Script:getParent()
	return self._data.parent
end

function Script:getWritingSystems()
	if not self._systemCodes then
        if type(self._data[3]) == "string" then
            self._systemCodes = split(self._data[3], "%s*,%s*")
        elseif type(self._data[3]) == "nil" then
            self._systemCodes = {}
        else
            error("mal el tipo de dato")
        end
	end
	return self._systemCodes
end

function Script:makeCategoryLink()
	return "[[:Categoría:" .. self:getDisplayForm() .. "]]"
end

--[==[Returns the regex defining the script's characters from the language's data file.
This can be used to search for words consisting only of this script, but see the warning above.]==]
function Script:getCharacters()
	return self.characters or nil
end

--[==[Returns the number of characters in the text that are part of this script.
'''Note:''' You should never rely on text consisting entirely of the same script. Strings may contain spaces, punctuation and even wiki markup or HTML tags. HTML tags will skew the counts, as they contain Latin-script characters. So it's best to avoid them.]==]
function Script:countCharacters(text)
	local charset = self._data.characters
	if charset == nil then
		return 0
	end
	return select(2, ugsub(text, "[" .. charset .. "]", ""))
end

function Script:hasCapitalization()
	return not not self._data.capitalized
end

function Script:hasSpaces()
	return self._data.spaces ~= false
end

function Script:isTransliterated()
	return self._data.translit ~= false
end

--[==[Returns true if the script is (sometimes) sorted by scraping page content, meaning that it is sensitive to changes in capitalization during sorting.]==]
function Script:sortByScraping()
	return not not self._data.sort_by_scraping
end

--[==[Returns the text direction, if any.]==]
function Script:getDirection()
	return self._data.direction or "ltr"
end

function Script:getData()
	return self._data
end

--[==[Returns {{code|lua|true}} if the script contains characters that require fixes to Unicode normalization under certain circumstances, {{code|lua|false}} if it doesn't.]==]
function Script:hasNormalizationFixes()
	return not not self._data.normalizationFixes
end

function Script:fixDiscouragedSequences(text)
	if self:hasNormalizationFixes() then
		local norm_fixes = self._data.normalizationFixes
		local to = norm_fixes.to
		if to then
			for i, v in ipairs(norm_fixes.from) do
				text = ugsub(text, v, to[i] or "")
			end
		end
	end
end

do
	local combining_classes
	
	-- Obtain the list of default combining classes.
	local function get_combining_classes()
		combining_classes, get_combining_classes = require(combining_classes_module), nil
		return combining_classes
	end
	
	-- Implements a modified form of Unicode normalization for instances where there are identified deficiencies in the default Unicode combining classes.
	local function fixNormalization(text, self)
		if not self:hasNormalizationFixes() then
			return text
		end
		local norm_fixes = self._data.normalizationFixes
		local new_classes = norm_fixes.combiningClasses
		if not (new_classes and umatch(text, "[" .. norm_fixes.combiningClassCharacters .. "]")) then
			return text
		end
		text = split(text, "")
		-- Manual sort based on new combining classes.
		-- We can't use table.sort, as it compares the first/last values in an array as a shortcut, which messes things up.
		for i = 2, #text do
			local char = text[i]
			local class = new_classes[char] or (combining_classes or get_combining_classes())[char]
			if class then
				repeat
					i = i - 1
					local prev = text[i]
					if (new_classes[prev] or (combining_classes or get_combining_classes())[prev] or 0) < class then
						break
					end
					text[i], text[i + 1] = char, prev
				until i == 1
			end
		end
		return concat(text)
	end
	
	function Script:toFixedNFC(text)
		return fixNormalization(toNFC(text), self)
	end
	
	function Script:toFixedNFD(text)
		return fixNormalization(toNFD(text), self)
	end
	
	function Script:toFixedNFKC(text)
		return fixNormalization(toNFKC(text), self)
	end
	
	function Script:toFixedNFKD(text)
		return fixNormalization(toNFKD(text), self)
	end
end

function export.makeObject(code, data)
	local data_type = type(data)
	if data_type ~= "table" then
		error(("bad argument #2 to 'makeObject' (table expected, got %s)"):format(data_type))
	end
	return setmetatable({_data = data, _code = code, characters = data.characters}, Script)
end

make_object = export.makeObject

--[==[
Finds the script whose code matches the one provided. If it exists, it returns a {Script} object representing the
script. Otherwise, it returns {nil}.]==]
function export.getByCode(code)
	local data = (scripts_data or get_scripts_data())[code]
	return data ~= nil and make_object(code, data) or nil
end
get_by_code = export.getByCode

return export