Compare commits
10 Commits
6b46f42dcc
...
53e3bd42c9
Author | SHA1 | Date | |
---|---|---|---|
|
53e3bd42c9 | ||
|
b9daec14d6 | ||
|
0c4d938a7b | ||
|
29b3067ff7 | ||
|
f65fa6d331 | ||
|
0ef6f0fa94 | ||
|
a8d57a7f9d | ||
|
2db4e84aa1 | ||
|
f132140e46 | ||
|
fbfe532f5b |
26
LICENSE.txt
26
LICENSE.txt
@ -1,18 +1,22 @@
|
|||||||
Copyright (C) 2017 FaceDeer
|
Copyright (C) 2017 FaceDeer
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
the Free Software Foundation; either version 2.1 of the License, or
|
in the Software without restriction, including without limitation the rights
|
||||||
(at your option) any later version.
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
The above copyright notice and this permission notice shall be included in all
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
copies or substantial portions of the Software.
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License along
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
License for Textures
|
License for Textures
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
default?
|
default?
|
||||||
doc?
|
doc?
|
||||||
intllib?
|
|
||||||
farming?
|
farming?
|
||||||
vines?
|
vines?
|
||||||
loot?
|
loot?
|
421
i18n.py
Normal file
421
i18n.py
Normal file
@ -0,0 +1,421 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Script to generate the template file and update the translation files.
|
||||||
|
# Copy the script into the mod or modpack root folder and run it there.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2019 Joachim Stolberg, 2020 FaceDeer, 2020 Louis Royer
|
||||||
|
# LGPLv2.1+
|
||||||
|
#
|
||||||
|
# See https://github.com/minetest-tools/update_translations for
|
||||||
|
# potential future updates to this script.
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
import os, fnmatch, re, shutil, errno
|
||||||
|
from sys import argv as _argv
|
||||||
|
|
||||||
|
# Running params
|
||||||
|
params = {"recursive": False,
|
||||||
|
"help": False,
|
||||||
|
"mods": False,
|
||||||
|
"verbose": False,
|
||||||
|
"folders": []
|
||||||
|
}
|
||||||
|
# Available CLI options
|
||||||
|
options = {"recursive": ['--recursive', '-r'],
|
||||||
|
"help": ['--help', '-h'],
|
||||||
|
"mods": ['--installed-mods'],
|
||||||
|
"verbose": ['--verbose', '-v']
|
||||||
|
}
|
||||||
|
|
||||||
|
# Strings longer than this will have extra space added between
|
||||||
|
# them in the translation files to make it easier to distinguish their
|
||||||
|
# beginnings and endings at a glance
|
||||||
|
doublespace_threshold = 60
|
||||||
|
|
||||||
|
def set_params_folders(tab: list):
|
||||||
|
'''Initialize params["folders"] from CLI arguments.'''
|
||||||
|
# Discarding argument 0 (tool name)
|
||||||
|
for param in tab[1:]:
|
||||||
|
stop_param = False
|
||||||
|
for option in options:
|
||||||
|
if param in options[option]:
|
||||||
|
stop_param = True
|
||||||
|
break
|
||||||
|
if not stop_param:
|
||||||
|
params["folders"].append(os.path.abspath(param))
|
||||||
|
|
||||||
|
def set_params(tab: list):
|
||||||
|
'''Initialize params from CLI arguments.'''
|
||||||
|
for option in options:
|
||||||
|
for option_name in options[option]:
|
||||||
|
if option_name in tab:
|
||||||
|
params[option] = True
|
||||||
|
break
|
||||||
|
|
||||||
|
def print_help(name):
|
||||||
|
'''Prints some help message.'''
|
||||||
|
print(f'''SYNOPSIS
|
||||||
|
{name} [OPTIONS] [PATHS...]
|
||||||
|
DESCRIPTION
|
||||||
|
{', '.join(options["help"])}
|
||||||
|
prints this help message
|
||||||
|
{', '.join(options["recursive"])}
|
||||||
|
run on all subfolders of paths given
|
||||||
|
{', '.join(options["mods"])}
|
||||||
|
run on locally installed modules
|
||||||
|
{', '.join(options["verbose"])}
|
||||||
|
add output information
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
'''Main function'''
|
||||||
|
set_params(_argv)
|
||||||
|
set_params_folders(_argv)
|
||||||
|
if params["help"]:
|
||||||
|
print_help(_argv[0])
|
||||||
|
elif params["recursive"] and params["mods"]:
|
||||||
|
print("Option --installed-mods is incompatible with --recursive")
|
||||||
|
else:
|
||||||
|
# Add recursivity message
|
||||||
|
print("Running ", end='')
|
||||||
|
if params["recursive"]:
|
||||||
|
print("recursively ", end='')
|
||||||
|
# Running
|
||||||
|
if params["mods"]:
|
||||||
|
print(f"on all locally installed modules in {os.path.abspath('~/.minetest/mods/')}")
|
||||||
|
run_all_subfolders("~/.minetest/mods")
|
||||||
|
elif len(params["folders"]) >= 2:
|
||||||
|
print("on folder list:", params["folders"])
|
||||||
|
for f in params["folders"]:
|
||||||
|
if params["recursive"]:
|
||||||
|
run_all_subfolders(f)
|
||||||
|
else:
|
||||||
|
update_folder(f)
|
||||||
|
elif len(params["folders"]) == 1:
|
||||||
|
print("on folder", params["folders"][0])
|
||||||
|
if params["recursive"]:
|
||||||
|
run_all_subfolders(params["folders"][0])
|
||||||
|
else:
|
||||||
|
update_folder(params["folders"][0])
|
||||||
|
else:
|
||||||
|
print("on folder", os.path.abspath("./"))
|
||||||
|
if params["recursive"]:
|
||||||
|
run_all_subfolders(os.path.abspath("./"))
|
||||||
|
else:
|
||||||
|
update_folder(os.path.abspath("./"))
|
||||||
|
|
||||||
|
#group 2 will be the string, groups 1 and 3 will be the delimiters (" or ')
|
||||||
|
#See https://stackoverflow.com/questions/46967465/regex-match-text-in-either-single-or-double-quote
|
||||||
|
pattern_lua = re.compile(r'[\.=^\t,{\(\s]N?S\(\s*(["\'])((?:\\\1|(?:(?!\1)).)*)(\1)[\s,\)]', re.DOTALL)
|
||||||
|
pattern_lua_bracketed = re.compile(r'[\.=^\t,{\(\s]N?S\(\s*\[\[(.*?)\]\][\s,\)]', re.DOTALL)
|
||||||
|
|
||||||
|
# Handles "concatenation" .. " of strings"
|
||||||
|
pattern_concat = re.compile(r'["\'][\s]*\.\.[\s]*["\']', re.DOTALL)
|
||||||
|
|
||||||
|
pattern_tr = re.compile(r'(.+?[^@])=(.*)')
|
||||||
|
pattern_name = re.compile(r'^name[ ]*=[ ]*([^ \n]*)')
|
||||||
|
pattern_tr_filename = re.compile(r'\.tr$')
|
||||||
|
pattern_po_language_code = re.compile(r'(.*)\.po$')
|
||||||
|
|
||||||
|
#attempt to read the mod's name from the mod.conf file. Returns None on failure
|
||||||
|
def get_modname(folder):
|
||||||
|
try:
|
||||||
|
with open(os.path.join(folder, "mod.conf"), "r", encoding='utf-8') as mod_conf:
|
||||||
|
for line in mod_conf:
|
||||||
|
match = pattern_name.match(line)
|
||||||
|
if match:
|
||||||
|
return match.group(1)
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
#If there are already .tr files in /locale, returns a list of their names
|
||||||
|
def get_existing_tr_files(folder):
|
||||||
|
out = []
|
||||||
|
for root, dirs, files in os.walk(os.path.join(folder, 'locale/')):
|
||||||
|
for name in files:
|
||||||
|
if pattern_tr_filename.search(name):
|
||||||
|
out.append(name)
|
||||||
|
return out
|
||||||
|
|
||||||
|
# A series of search and replaces that massage a .po file's contents into
|
||||||
|
# a .tr file's equivalent
|
||||||
|
def process_po_file(text):
|
||||||
|
# The first three items are for unused matches
|
||||||
|
text = re.sub(r'#~ msgid "', "", text)
|
||||||
|
text = re.sub(r'"\n#~ msgstr ""\n"', "=", text)
|
||||||
|
text = re.sub(r'"\n#~ msgstr "', "=", text)
|
||||||
|
# comment lines
|
||||||
|
text = re.sub(r'#.*\n', "", text)
|
||||||
|
# converting msg pairs into "=" pairs
|
||||||
|
text = re.sub(r'msgid "', "", text)
|
||||||
|
text = re.sub(r'"\nmsgstr ""\n"', "=", text)
|
||||||
|
text = re.sub(r'"\nmsgstr "', "=", text)
|
||||||
|
# various line breaks and escape codes
|
||||||
|
text = re.sub(r'"\n"', "", text)
|
||||||
|
text = re.sub(r'"\n', "\n", text)
|
||||||
|
text = re.sub(r'\\"', '"', text)
|
||||||
|
text = re.sub(r'\\n', '@n', text)
|
||||||
|
# remove header text
|
||||||
|
text = re.sub(r'=Project-Id-Version:.*\n', "", text)
|
||||||
|
# remove double-spaced lines
|
||||||
|
text = re.sub(r'\n\n', '\n', text)
|
||||||
|
return text
|
||||||
|
|
||||||
|
# Go through existing .po files and, if a .tr file for that language
|
||||||
|
# *doesn't* exist, convert it and create it.
|
||||||
|
# The .tr file that results will subsequently be reprocessed so
|
||||||
|
# any "no longer used" strings will be preserved.
|
||||||
|
# Note that "fuzzy" tags will be lost in this process.
|
||||||
|
def process_po_files(folder, modname):
|
||||||
|
for root, dirs, files in os.walk(os.path.join(folder, 'locale/')):
|
||||||
|
for name in files:
|
||||||
|
code_match = pattern_po_language_code.match(name)
|
||||||
|
if code_match == None:
|
||||||
|
continue
|
||||||
|
language_code = code_match.group(1)
|
||||||
|
tr_name = modname + "." + language_code + ".tr"
|
||||||
|
tr_file = os.path.join(root, tr_name)
|
||||||
|
if os.path.exists(tr_file):
|
||||||
|
if params["verbose"]:
|
||||||
|
print(f"{tr_name} already exists, ignoring {name}")
|
||||||
|
continue
|
||||||
|
fname = os.path.join(root, name)
|
||||||
|
with open(fname, "r", encoding='utf-8') as po_file:
|
||||||
|
if params["verbose"]:
|
||||||
|
print(f"Importing translations from {name}")
|
||||||
|
text = process_po_file(po_file.read())
|
||||||
|
with open(tr_file, "wt", encoding='utf-8') as tr_out:
|
||||||
|
tr_out.write(text)
|
||||||
|
|
||||||
|
# from https://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python/600612#600612
|
||||||
|
# Creates a directory if it doesn't exist, silently does
|
||||||
|
# nothing if it already exists
|
||||||
|
def mkdir_p(path):
|
||||||
|
try:
|
||||||
|
os.makedirs(path)
|
||||||
|
except OSError as exc: # Python >2.5
|
||||||
|
if exc.errno == errno.EEXIST and os.path.isdir(path):
|
||||||
|
pass
|
||||||
|
else: raise
|
||||||
|
|
||||||
|
# Converts the template dictionary to a text to be written as a file
|
||||||
|
# dKeyStrings is a dictionary of localized string to source file sets
|
||||||
|
# dOld is a dictionary of existing translations and comments from
|
||||||
|
# the previous version of this text
|
||||||
|
def strings_to_text(dkeyStrings, dOld, mod_name):
|
||||||
|
lOut = [f"# textdomain: {mod_name}\n"]
|
||||||
|
|
||||||
|
dGroupedBySource = {}
|
||||||
|
|
||||||
|
for key in dkeyStrings:
|
||||||
|
sourceList = list(dkeyStrings[key])
|
||||||
|
sourceList.sort()
|
||||||
|
sourceString = "\n".join(sourceList)
|
||||||
|
listForSource = dGroupedBySource.get(sourceString, [])
|
||||||
|
listForSource.append(key)
|
||||||
|
dGroupedBySource[sourceString] = listForSource
|
||||||
|
|
||||||
|
lSourceKeys = list(dGroupedBySource.keys())
|
||||||
|
lSourceKeys.sort()
|
||||||
|
for source in lSourceKeys:
|
||||||
|
localizedStrings = dGroupedBySource[source]
|
||||||
|
localizedStrings.sort()
|
||||||
|
lOut.append("")
|
||||||
|
lOut.append(source)
|
||||||
|
lOut.append("")
|
||||||
|
for localizedString in localizedStrings:
|
||||||
|
val = dOld.get(localizedString, {})
|
||||||
|
translation = val.get("translation", "")
|
||||||
|
comment = val.get("comment")
|
||||||
|
if len(localizedString) > doublespace_threshold and not lOut[-1] == "":
|
||||||
|
lOut.append("")
|
||||||
|
if comment != None:
|
||||||
|
lOut.append(comment)
|
||||||
|
lOut.append(f"{localizedString}={translation}")
|
||||||
|
if len(localizedString) > doublespace_threshold:
|
||||||
|
lOut.append("")
|
||||||
|
|
||||||
|
|
||||||
|
unusedExist = False
|
||||||
|
for key in dOld:
|
||||||
|
if key not in dkeyStrings:
|
||||||
|
val = dOld[key]
|
||||||
|
translation = val.get("translation")
|
||||||
|
comment = val.get("comment")
|
||||||
|
# only keep an unused translation if there was translated
|
||||||
|
# text or a comment associated with it
|
||||||
|
if translation != None and (translation != "" or comment):
|
||||||
|
if not unusedExist:
|
||||||
|
unusedExist = True
|
||||||
|
lOut.append("\n\n##### not used anymore #####\n")
|
||||||
|
if len(key) > doublespace_threshold and not lOut[-1] == "":
|
||||||
|
lOut.append("")
|
||||||
|
if comment != None:
|
||||||
|
lOut.append(comment)
|
||||||
|
lOut.append(f"{key}={translation}")
|
||||||
|
if len(key) > doublespace_threshold:
|
||||||
|
lOut.append("")
|
||||||
|
return "\n".join(lOut) + '\n'
|
||||||
|
|
||||||
|
# Writes a template.txt file
|
||||||
|
# dkeyStrings is the dictionary returned by generate_template
|
||||||
|
def write_template(templ_file, dkeyStrings, mod_name):
|
||||||
|
# read existing template file to preserve comments
|
||||||
|
existing_template = import_tr_file(templ_file)
|
||||||
|
|
||||||
|
text = strings_to_text(dkeyStrings, existing_template[0], mod_name)
|
||||||
|
mkdir_p(os.path.dirname(templ_file))
|
||||||
|
with open(templ_file, "wt", encoding='utf-8') as template_file:
|
||||||
|
template_file.write(text)
|
||||||
|
|
||||||
|
|
||||||
|
# Gets all translatable strings from a lua file
|
||||||
|
def read_lua_file_strings(lua_file):
|
||||||
|
lOut = []
|
||||||
|
with open(lua_file, encoding='utf-8') as text_file:
|
||||||
|
text = text_file.read()
|
||||||
|
#TODO remove comments here
|
||||||
|
|
||||||
|
text = re.sub(pattern_concat, "", text)
|
||||||
|
|
||||||
|
strings = []
|
||||||
|
for s in pattern_lua.findall(text):
|
||||||
|
strings.append(s[1])
|
||||||
|
for s in pattern_lua_bracketed.findall(text):
|
||||||
|
strings.append(s)
|
||||||
|
|
||||||
|
for s in strings:
|
||||||
|
s = re.sub(r'"\.\.\s+"', "", s)
|
||||||
|
s = re.sub("@[^@=0-9]", "@@", s)
|
||||||
|
s = s.replace('\\"', '"')
|
||||||
|
s = s.replace("\\'", "'")
|
||||||
|
s = s.replace("\n", "@n")
|
||||||
|
s = s.replace("\\n", "@n")
|
||||||
|
s = s.replace("=", "@=")
|
||||||
|
lOut.append(s)
|
||||||
|
return lOut
|
||||||
|
|
||||||
|
# Gets strings from an existing translation file
|
||||||
|
# returns both a dictionary of translations
|
||||||
|
# and the full original source text so that the new text
|
||||||
|
# can be compared to it for changes.
|
||||||
|
def import_tr_file(tr_file):
|
||||||
|
dOut = {}
|
||||||
|
text = None
|
||||||
|
if os.path.exists(tr_file):
|
||||||
|
with open(tr_file, "r", encoding='utf-8') as existing_file :
|
||||||
|
# save the full text to allow for comparison
|
||||||
|
# of the old version with the new output
|
||||||
|
text = existing_file.read()
|
||||||
|
existing_file.seek(0)
|
||||||
|
# a running record of the current comment block
|
||||||
|
# we're inside, to allow preceeding multi-line comments
|
||||||
|
# to be retained for a translation line
|
||||||
|
latest_comment_block = None
|
||||||
|
for line in existing_file.readlines():
|
||||||
|
line = line.rstrip('\n')
|
||||||
|
if line[:3] == "###":
|
||||||
|
# Reset comment block if we hit a header
|
||||||
|
latest_comment_block = None
|
||||||
|
continue
|
||||||
|
if line[:1] == "#":
|
||||||
|
# Save the comment we're inside
|
||||||
|
if not latest_comment_block:
|
||||||
|
latest_comment_block = line
|
||||||
|
else:
|
||||||
|
latest_comment_block = latest_comment_block + "\n" + line
|
||||||
|
continue
|
||||||
|
match = pattern_tr.match(line)
|
||||||
|
if match:
|
||||||
|
# this line is a translated line
|
||||||
|
outval = {}
|
||||||
|
outval["translation"] = match.group(2)
|
||||||
|
if latest_comment_block:
|
||||||
|
# if there was a comment, record that.
|
||||||
|
outval["comment"] = latest_comment_block
|
||||||
|
latest_comment_block = None
|
||||||
|
dOut[match.group(1)] = outval
|
||||||
|
return (dOut, text)
|
||||||
|
|
||||||
|
# Walks all lua files in the mod folder, collects translatable strings,
|
||||||
|
# and writes it to a template.txt file
|
||||||
|
# Returns a dictionary of localized strings to source file sets
|
||||||
|
# that can be used with the strings_to_text function.
|
||||||
|
def generate_template(folder, mod_name):
|
||||||
|
dOut = {}
|
||||||
|
for root, dirs, files in os.walk(folder):
|
||||||
|
for name in files:
|
||||||
|
if fnmatch.fnmatch(name, "*.lua"):
|
||||||
|
fname = os.path.join(root, name)
|
||||||
|
found = read_lua_file_strings(fname)
|
||||||
|
if params["verbose"]:
|
||||||
|
print(f"{fname}: {str(len(found))} translatable strings")
|
||||||
|
|
||||||
|
for s in found:
|
||||||
|
sources = dOut.get(s, set())
|
||||||
|
sources.add(f"### {os.path.basename(fname)} ###")
|
||||||
|
dOut[s] = sources
|
||||||
|
|
||||||
|
if len(dOut) == 0:
|
||||||
|
return None
|
||||||
|
templ_file = os.path.join(folder, "locale/template.txt")
|
||||||
|
write_template(templ_file, dOut, mod_name)
|
||||||
|
return dOut
|
||||||
|
|
||||||
|
# Updates an existing .tr file, copying the old one to a ".old" file
|
||||||
|
# if any changes have happened
|
||||||
|
# dNew is the data used to generate the template, it has all the
|
||||||
|
# currently-existing localized strings
|
||||||
|
def update_tr_file(dNew, mod_name, tr_file):
|
||||||
|
if params["verbose"]:
|
||||||
|
print(f"updating {tr_file}")
|
||||||
|
|
||||||
|
tr_import = import_tr_file(tr_file)
|
||||||
|
dOld = tr_import[0]
|
||||||
|
textOld = tr_import[1]
|
||||||
|
|
||||||
|
textNew = strings_to_text(dNew, dOld, mod_name)
|
||||||
|
|
||||||
|
if textOld and textOld != textNew:
|
||||||
|
print(f"{tr_file} has changed.")
|
||||||
|
shutil.copyfile(tr_file, f"{tr_file}.old")
|
||||||
|
|
||||||
|
with open(tr_file, "w", encoding='utf-8') as new_tr_file:
|
||||||
|
new_tr_file.write(textNew)
|
||||||
|
|
||||||
|
# Updates translation files for the mod in the given folder
|
||||||
|
def update_mod(folder):
|
||||||
|
modname = get_modname(folder)
|
||||||
|
if modname is not None:
|
||||||
|
process_po_files(folder, modname)
|
||||||
|
print(f"Updating translations for {modname}")
|
||||||
|
data = generate_template(folder, modname)
|
||||||
|
if data == None:
|
||||||
|
print(f"No translatable strings found in {modname}")
|
||||||
|
else:
|
||||||
|
for tr_file in get_existing_tr_files(folder):
|
||||||
|
update_tr_file(data, modname, os.path.join(folder, "locale/", tr_file))
|
||||||
|
else:
|
||||||
|
print("Unable to find modname in folder " + folder)
|
||||||
|
|
||||||
|
# Determines if the folder being pointed to is a mod or a mod pack
|
||||||
|
# and then runs update_mod accordingly
|
||||||
|
def update_folder(folder):
|
||||||
|
is_modpack = os.path.exists(os.path.join(folder, "modpack.txt")) or os.path.exists(os.path.join(folder, "modpack.conf"))
|
||||||
|
if is_modpack:
|
||||||
|
subfolders = [f.path for f in os.scandir(folder) if f.is_dir()]
|
||||||
|
for subfolder in subfolders:
|
||||||
|
update_mod(subfolder + "/")
|
||||||
|
else:
|
||||||
|
update_mod(folder)
|
||||||
|
print("Done.")
|
||||||
|
|
||||||
|
def run_all_subfolders(folder):
|
||||||
|
for modfolder in [f.path for f in os.scandir(folder) if f.is_dir()]:
|
||||||
|
update_folder(modfolder + "/")
|
||||||
|
|
||||||
|
|
||||||
|
main()
|
94
init.lua
94
init.lua
@ -1,6 +1,5 @@
|
|||||||
-- internationalization boilerplate
|
local modname = minetest.get_current_modname()
|
||||||
local MP = minetest.get_modpath(minetest.get_current_modname())
|
local S = minetest.get_translator(modname)
|
||||||
local S, NS = dofile(MP.."/intllib.lua")
|
|
||||||
|
|
||||||
local data = {}
|
local data = {}
|
||||||
|
|
||||||
@ -9,23 +8,27 @@ if minetest.get_modpath("default") then
|
|||||||
node_sound = default.node_sound_wood_defaults()
|
node_sound = default.node_sound_wood_defaults()
|
||||||
end
|
end
|
||||||
|
|
||||||
local particles = minetest.setting_get("enable_particles")
|
local particles = minetest.settings:get_bool("enable_particles", true)
|
||||||
if particles == "true" or particles == nil then
|
|
||||||
particles = true -- default true
|
local longdesc
|
||||||
else
|
local usagehelp
|
||||||
particles = false
|
|
||||||
|
if minetest.get_modpath("doc") then
|
||||||
|
longdesc = S("A spool of marked line with a weight on the end used for measuring depths.")
|
||||||
|
usagehelp = S("Build this item over the location whose depths you wish to plumb. Right click on it to take a reading. The sounding line will give a reading indicating how far down the sounding line encountered water (if any) and how far down the first solid obstruction is.\n\nIf lava is encountered this will be indicated by a burnt end on the line. Sounding lines can't measure the depth of lava, only how far it is to the lava's surface.\n\nIf the sounding line reports encountering an \"unknown void\" it has reached a region that has not yet been generated by map generation.")
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_node("sounding_line:sounding_line", {
|
minetest.register_node("sounding_line:sounding_line", {
|
||||||
description = S("Sounding Line"),
|
description = S("Sounding Line"),
|
||||||
_doc_items_longdesc = S("A spool of marked line with a weight on the end used for measuring depths."),
|
_doc_items_longdesc = longdesc,
|
||||||
_doc_items_usagehelp = S("Build this item over the location whose depths you wish to plumb. Right click on it to take a reading. The sounding line will give a reading indicating how far down the sounding line encountered water (if any) and how far down the first solid obstruction is.\n\nIf lava is encountered this will be indicated by a burnt end on the line. Sounding lines can't measure the depth of lava, only how far it is to the lava's surface.\n\nIf the sounding line reports encountering an \"unknown void\" it has reached a region that has not yet been generated by map generation."),
|
_doc_items_usagehelp = usagehelp,
|
||||||
groups = {cracky = 3, oddly_breakable_by_hand=3},
|
groups = {cracky = 3, oddly_breakable_by_hand=3},
|
||||||
drop = "sounding_line:sounding_line",
|
drop = "sounding_line:sounding_line",
|
||||||
tiles = {"sounding_line_top.png","sounding_line_bottom.png",
|
tiles = {"sounding_line_top.png","sounding_line_bottom.png",
|
||||||
"sounding_line_side.png","sounding_line_side.png^[transformFX",
|
"sounding_line_side.png","sounding_line_side.png^[transformFX",
|
||||||
"sounding_line_front.png","sounding_line_front.png^[transformFX"},
|
"sounding_line_front.png","sounding_line_front.png^[transformFX"},
|
||||||
sounds = node_sound,
|
sounds = node_sound,
|
||||||
|
use_texture_alpha = "clip",
|
||||||
climbable = true,
|
climbable = true,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
@ -72,7 +75,7 @@ minetest.register_node("sounding_line:sounding_line", {
|
|||||||
water_depth = pos.y - y
|
water_depth = pos.y - y
|
||||||
end
|
end
|
||||||
if not encountered_lava and minetest.get_item_group(name, "lava") > 0 then
|
if not encountered_lava and minetest.get_item_group(name, "lava") > 0 then
|
||||||
end_depth = y - pos.y
|
end_depth = pos.y - y
|
||||||
encountered_lava = true
|
encountered_lava = true
|
||||||
end
|
end
|
||||||
local def = minetest.registered_nodes[name]
|
local def = minetest.registered_nodes[name]
|
||||||
@ -88,16 +91,26 @@ minetest.register_node("sounding_line:sounding_line", {
|
|||||||
bottom = bottom - 15
|
bottom = bottom - 15
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local player_name = player:get_player_name()
|
||||||
|
|
||||||
local status = S("Most recent reading:")
|
local status = S("Most recent reading:")
|
||||||
if water_depth then
|
if water_depth then
|
||||||
status = status .. "\n" .. string.format(S("Water %dm down"), water_depth)
|
local result = S("Water @1m down", water_depth)
|
||||||
|
minetest.chat_send_player(player_name, result)
|
||||||
|
status = status .. "\n" .. result
|
||||||
end
|
end
|
||||||
if encountered_lava then
|
if encountered_lava then
|
||||||
status = status .. "\n" .. string.format(S("Line burned %dm down"), end_depth)
|
local result = S("Line burned @1m down", end_depth)
|
||||||
|
minetest.chat_send_player(player_name, result)
|
||||||
|
status = status .. "\n" .. result
|
||||||
elseif encountered_ignore then
|
elseif encountered_ignore then
|
||||||
status = status .. "\n" .. string.format(S("Unknown void %dm down"), end_depth)
|
local result = S("Unknown void @1m down", end_depth)
|
||||||
|
minetest.chat_send_player(player_name, result)
|
||||||
|
status = status .. "\n" .. result
|
||||||
else
|
else
|
||||||
status = status .. "\n" .. string.format(S("Obstruction %dm down"), end_depth)
|
local result = S("Obstruction @1m down", end_depth)
|
||||||
|
minetest.chat_send_player(player_name, result)
|
||||||
|
status = status .. "\n" .. result
|
||||||
end
|
end
|
||||||
|
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
@ -123,31 +136,38 @@ minetest.register_node("sounding_line:sounding_line", {
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.sound_play("sounding_line_whooshing", {pos=pos})
|
minetest.sound_play("sounding_line_whooshing", {pos=pos, gain=0.5})
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if minetest.get_modpath("farming") then
|
||||||
|
local old_def = minetest.registered_craftitems["farming:cotton"]
|
||||||
|
if old_def then
|
||||||
|
old_def.groups["thread"] = 1
|
||||||
|
minetest.override_item("farming:cotton", {
|
||||||
|
groups = old_def.groups
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if minetest.get_modpath("default") then
|
if minetest.get_modpath("default") then
|
||||||
if minetest.get_modpath("farming") then
|
minetest.register_craft({
|
||||||
minetest.register_craft({
|
output = "sounding_line:sounding_line",
|
||||||
output = "sounding_line:sounding_line",
|
recipe = {
|
||||||
recipe = {
|
{'group:stick','group:stick','group:stick'},
|
||||||
{'group:stick','group:stick','group:stick'},
|
{'group:thread','group:thread','group:thread'},
|
||||||
{'farming:cotton','farming:cotton','farming:cotton'},
|
{'','default:steel_ingot',''}
|
||||||
{'','default:steel_ingot',''}
|
}
|
||||||
}
|
})
|
||||||
})
|
|
||||||
end
|
minetest.register_craft({
|
||||||
if minetest.get_modpath("vines") then
|
output = "sounding_line:sounding_line",
|
||||||
minetest.register_craft({
|
recipe = {
|
||||||
output = "sounding_line:sounding_line",
|
{'group:stick','group:stick','group:stick'},
|
||||||
recipe = {
|
{'','group:vines',''},
|
||||||
{'group:stick','group:stick','group:stick'},
|
{'','default:steel_ingot',''}
|
||||||
{'','group:vines',''},
|
}
|
||||||
{'','default:steel_ingot',''}
|
})
|
||||||
}
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if minetest.get_modpath("loot") then
|
if minetest.get_modpath("loot") then
|
||||||
@ -159,4 +179,4 @@ if minetest.get_modpath("loot") then
|
|||||||
max_size = 4,
|
max_size = 4,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
45
intllib.lua
45
intllib.lua
@ -1,45 +0,0 @@
|
|||||||
|
|
||||||
-- Fallback functions for when `intllib` is not installed.
|
|
||||||
-- Code released under Unlicense <http://unlicense.org>.
|
|
||||||
|
|
||||||
-- Get the latest version of this file at:
|
|
||||||
-- https://raw.githubusercontent.com/minetest-mods/intllib/master/lib/intllib.lua
|
|
||||||
|
|
||||||
local function format(str, ...)
|
|
||||||
local args = { ... }
|
|
||||||
local function repl(escape, open, num, close)
|
|
||||||
if escape == "" then
|
|
||||||
local replacement = tostring(args[tonumber(num)])
|
|
||||||
if open == "" then
|
|
||||||
replacement = replacement..close
|
|
||||||
end
|
|
||||||
return replacement
|
|
||||||
else
|
|
||||||
return "@"..open..num..close
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return (str:gsub("(@?)@(%(?)(%d+)(%)?)", repl))
|
|
||||||
end
|
|
||||||
|
|
||||||
local gettext, ngettext
|
|
||||||
if minetest.get_modpath("intllib") then
|
|
||||||
if intllib.make_gettext_pair then
|
|
||||||
-- New method using gettext.
|
|
||||||
gettext, ngettext = intllib.make_gettext_pair()
|
|
||||||
else
|
|
||||||
-- Old method using text files.
|
|
||||||
gettext = intllib.Getter()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Fill in missing functions.
|
|
||||||
|
|
||||||
gettext = gettext or function(msgid, ...)
|
|
||||||
return format(msgid, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
ngettext = ngettext or function(msgid, msgid_plural, n, ...)
|
|
||||||
return format(n==1 and msgid or msgid_plural, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
return gettext, ngettext
|
|
@ -1,65 +0,0 @@
|
|||||||
# SOME DESCRIPTIVE TITLE.
|
|
||||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
|
||||||
#
|
|
||||||
#, fuzzy
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2017-02-05 12:32-0700\n"
|
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=CHARSET\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
|
|
||||||
#: init.lua:13
|
|
||||||
msgid "Sounding Line"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: init.lua:14
|
|
||||||
msgid ""
|
|
||||||
"A spool of marked line with a weight on the end used for measuring depths."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: init.lua:15
|
|
||||||
msgid ""
|
|
||||||
"Build this item over the location whose depths you wish to plumb. Right "
|
|
||||||
"click on it to take a reading. The sounding line will give a reading "
|
|
||||||
"indicating how far down the sounding line encountered water (if any) and how "
|
|
||||||
"far down the first solid obstruction is.\n"
|
|
||||||
"\n"
|
|
||||||
"If lava is encountered this will be indicated by a burnt end on the line. "
|
|
||||||
"Sounding lines can't measure the depth of lava, only how far it is to the "
|
|
||||||
"lava's surface.\n"
|
|
||||||
"\n"
|
|
||||||
"If the sounding line reports encountering an \"unknown void\" it has reached "
|
|
||||||
"a region that has not yet been generated by map generation."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: init.lua:84
|
|
||||||
msgid "Most recent reading:"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: init.lua:86
|
|
||||||
#, c-format
|
|
||||||
msgid "Water %dm down"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: init.lua:89
|
|
||||||
#, c-format
|
|
||||||
msgid "Line burned %dm down"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: init.lua:91
|
|
||||||
#, c-format
|
|
||||||
msgid "Unknown void %dm down"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: init.lua:93
|
|
||||||
#, c-format
|
|
||||||
msgid "Obstruction %dm down"
|
|
||||||
msgstr ""
|
|
16
locale/template.txt
Normal file
16
locale/template.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# textdomain: sounding_line
|
||||||
|
|
||||||
|
|
||||||
|
### init.lua ###
|
||||||
|
|
||||||
|
# ../sounding_line/init.lua
|
||||||
|
A spool of marked line with a weight on the end used for measuring depths.=
|
||||||
|
|
||||||
|
Build this item over the location whose depths you wish to plumb. Right click on it to take a reading. The sounding line will give a reading indicating how far down the sounding line encountered water (if any) and how far down the first solid obstruction is.@n@nIf lava is encountered this will be indicated by a burnt end on the line. Sounding lines can't measure the depth of lava, only how far it is to the lava's surface.@n@nIf the sounding line reports encountering an "unknown void" it has reached a region that has not yet been generated by map generation.=
|
||||||
|
|
||||||
|
Line burned @1m down=
|
||||||
|
Most recent reading:=
|
||||||
|
Obstruction @1m down=
|
||||||
|
Sounding Line=
|
||||||
|
Unknown void @1m down=
|
||||||
|
Water @1m down=
|
Loading…
x
Reference in New Issue
Block a user