forked from Minetest/dynamic_liquid
switch to native translator
parent
ab10a93181
commit
df13b27260
|
@ -0,0 +1,218 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- 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
|
||||
# LGPLv2.1+
|
||||
|
||||
from __future__ import print_function
|
||||
import os, fnmatch, re, shutil, errno
|
||||
|
||||
#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
|
||||
#TODO: support [[]] delimiters
|
||||
pattern_lua = re.compile(r'[\.=^\t,{\(\s]N?S\(\s*(["\'])((?:\\\1|(?:(?!\1)).)*)(\1)[\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(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(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(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):
|
||||
print(tr_name + " already exists, ignoring " + name)
|
||||
continue
|
||||
fname = os.path.join(root, name)
|
||||
with open(fname, "r", encoding='utf-8') as po_file:
|
||||
print("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
|
||||
|
||||
# Writes a template.txt file
|
||||
def write_template(templ_file, lkeyStrings):
|
||||
lOut = []
|
||||
lkeyStrings.sort()
|
||||
for s in lkeyStrings:
|
||||
lOut.append("%s=" % s)
|
||||
mkdir_p(os.path.dirname(templ_file))
|
||||
with open(templ_file, "wt", encoding='utf-8') as template_file:
|
||||
template_file.write("\n".join(lOut))
|
||||
|
||||
# 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()
|
||||
text = re.sub(pattern_concat, "", text)
|
||||
for s in pattern_lua.findall(text):
|
||||
s = s[1]
|
||||
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
|
||||
def import_tr_file(tr_file):
|
||||
dOut = {}
|
||||
if os.path.exists(tr_file):
|
||||
with open(tr_file, "r", encoding='utf-8') as existing_file :
|
||||
for line in existing_file.readlines():
|
||||
s = line.strip()
|
||||
if s == "" or s[0] == "#":
|
||||
continue
|
||||
match = pattern_tr.match(s)
|
||||
if match:
|
||||
dOut[match.group(1)] = match.group(2)
|
||||
return dOut
|
||||
|
||||
# Walks all lua files in the mod folder, collects translatable strings,
|
||||
# and writes it to a template.txt file
|
||||
def generate_template(folder):
|
||||
lOut = []
|
||||
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)
|
||||
print(fname + ": " + str(len(found)) + " translatable strings")
|
||||
lOut.extend(found)
|
||||
lOut = list(set(lOut))
|
||||
lOut.sort()
|
||||
if len(lOut) == 0:
|
||||
return None
|
||||
templ_file = folder + "locale/template.txt"
|
||||
write_template(templ_file, lOut)
|
||||
return lOut
|
||||
|
||||
# Updates an existing .tr file, copying the old one to a ".old" file
|
||||
def update_tr_file(lNew, mod_name, tr_file):
|
||||
print("updating " + tr_file)
|
||||
lOut = ["# textdomain: %s\n" % mod_name]
|
||||
|
||||
#TODO only make a .old if there are actual changes from the old file
|
||||
if os.path.exists(tr_file):
|
||||
shutil.copyfile(tr_file, tr_file+".old")
|
||||
|
||||
dOld = import_tr_file(tr_file)
|
||||
for key in lNew:
|
||||
val = dOld.get(key, "")
|
||||
lOut.append("%s=%s" % (key, val))
|
||||
lOut.append("##### not used anymore #####")
|
||||
for key in dOld:
|
||||
if key not in lNew:
|
||||
lOut.append("%s=%s" % (key, dOld[key]))
|
||||
with open(tr_file, "w", encoding='utf-8') as new_tr_file:
|
||||
new_tr_file.write("\n".join(lOut))
|
||||
|
||||
# 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("Updating translations for " + modname)
|
||||
data = generate_template(folder)
|
||||
if data == None:
|
||||
print("No translatable strings found in " + modname)
|
||||
else:
|
||||
for tr_file in get_existing_tr_files(folder):
|
||||
update_tr_file(data, modname, folder + "locale/" + tr_file)
|
||||
else:
|
||||
print("Unable to find modname in folder " + folder)
|
||||
|
||||
def update_folder(folder):
|
||||
is_modpack = os.path.exists(folder+"modpack.txt") or os.path.exists(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.")
|
||||
|
||||
|
||||
update_folder("./")
|
||||
|
||||
# Runs this script on each sub-folder in the parent folder.
|
||||
# I'm using this for testing this script on all installed mods.
|
||||
#for modfolder in [f.path for f in os.scandir("../") if f.is_dir()]:
|
||||
# update_folder(modfolder + "/")
|
8
init.lua
8
init.lua
|
@ -5,11 +5,11 @@ dynamic_liquid.registered_liquid_neighbors = {}
|
|||
|
||||
local water_level = tonumber(minetest.get_mapgen_setting("water_level"))
|
||||
|
||||
-- internationalization boilerplate
|
||||
local MP = minetest.get_modpath(minetest.get_current_modname())
|
||||
local S, NS = dofile(MP.."/intllib.lua")
|
||||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
local S = minetest.get_translator(modname)
|
||||
|
||||
dofile(MP.."/cooling_lava.lua")
|
||||
dofile(modpath.."/cooling_lava.lua")
|
||||
|
||||
-- By making this giant table of all possible permutations of horizontal direction we can avoid
|
||||
-- lots of redundant calculations.
|
||||
|
|
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
|
37
locale/de.po
37
locale/de.po
|
@ -1,37 +0,0 @@
|
|||
# Dynamic liquid Minetest mod.
|
||||
# Copyright (C) 2017
|
||||
# This file is distributed under the same license as the dynamic_liquid package.
|
||||
# FaceDeer
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-12 12:55-0700\n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: init.lua:141
|
||||
msgid "Damp Clay"
|
||||
msgstr "Feuchten Lehm"
|
||||
|
||||
#: init.lua:197
|
||||
msgid "Spring"
|
||||
msgstr "Quelle"
|
||||
|
||||
#: init.lua:198
|
||||
msgid ""
|
||||
"A natural spring that generates an endless stream of water source blocks"
|
||||
msgstr ""
|
||||
|
||||
#: init.lua:199
|
||||
msgid ""
|
||||
"Generates one source block of water directly on top of itself once per "
|
||||
"second, provided the space is clear. If this natural spring is dug out the "
|
||||
"flow stops and it is turned into ordinary cobble."
|
||||
msgstr ""
|
|
@ -0,0 +1,7 @@
|
|||
# textdomain: dynamic_liquid
|
||||
|
||||
A natural spring that generates an endless stream of water source blocks=
|
||||
Damp Clay=Feuchten Lehm
|
||||
Generates one source block of water directly on top of itself once per second, provided the space is clear. If this natural spring is dug out the flow stops and it is turned into ordinary cobble.=
|
||||
Spring=Quelle
|
||||
##### not used anymore #####
|
|
@ -0,0 +1,7 @@
|
|||
# textdomain: dynamic_liquid
|
||||
|
||||
A natural spring that generates an endless stream of water source blocks=Un manantial natural que genera un flujo sin fín de bloques fuente de agua
|
||||
Damp Clay=Arcilla húmeda
|
||||
Generates one source block of water directly on top of itself once per second, provided the space is clear. If this natural spring is dug out the flow stops and it is turned into ordinary cobble.=Genera un bloque fuente de agua directamente encima de sí mismo una vez por segundo, en tanto el espacio esté libre. Si éste manantial natural es excavado el flujo se detiene y se convierte en adoquines comúnes.
|
||||
Spring=Manantial
|
||||
##### not used anymore #####
|
|
@ -0,0 +1,7 @@
|
|||
# textdomain: dynamic_liquid
|
||||
|
||||
A natural spring that generates an endless stream of water source blocks=
|
||||
Damp Clay=Argile humide
|
||||
Generates one source block of water directly on top of itself once per second, provided the space is clear. If this natural spring is dug out the flow stops and it is turned into ordinary cobble.=
|
||||
Spring=Source
|
||||
##### not used anymore #####
|
43
locale/es.po
43
locale/es.po
|
@ -1,43 +0,0 @@
|
|||
# Spanish translations for PACKAGE package
|
||||
# Traducciones al español para el paquete PACKAGE.
|
||||
# Copyright (C) 2017 THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# Diego Martínez <kaeza@kaeza-desktop>, 2017.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-12 12:55-0700\n"
|
||||
"PO-Revision-Date: 2017-02-24 00:13-0300\n"
|
||||
"Last-Translator: Diego Martínez <kaeza@kaeza-desktop>\n"
|
||||
"Language-Team: Spanish\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: init.lua:141
|
||||
msgid "Damp Clay"
|
||||
msgstr "Arcilla húmeda"
|
||||
|
||||
#: init.lua:197
|
||||
msgid "Spring"
|
||||
msgstr "Manantial"
|
||||
|
||||
#: init.lua:198
|
||||
msgid ""
|
||||
"A natural spring that generates an endless stream of water source blocks"
|
||||
msgstr ""
|
||||
"Un manantial natural que genera un flujo sin fín de bloques fuente de agua"
|
||||
|
||||
#: init.lua:199
|
||||
msgid ""
|
||||
"Generates one source block of water directly on top of itself once per "
|
||||
"second, provided the space is clear. If this natural spring is dug out the "
|
||||
"flow stops and it is turned into ordinary cobble."
|
||||
msgstr ""
|
||||
"Genera un bloque fuente de agua directamente encima de sí mismo una vez por "
|
||||
"segundo, en tanto el espacio esté libre. Si éste manantial natural es "
|
||||
"excavado el flujo se detiene y se convierte en adoquines comúnes."
|
37
locale/fr.po
37
locale/fr.po
|
@ -1,37 +0,0 @@
|
|||
# Dynamic liquid Minetest mod.
|
||||
# Copyright (C) 2017
|
||||
# This file is distributed under the same license as the dynamic_liquid package.
|
||||
# FaceDeer
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-12 12:55-0700\n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: init.lua:141
|
||||
msgid "Damp Clay"
|
||||
msgstr "Argile humide"
|
||||
|
||||
#: init.lua:197
|
||||
msgid "Spring"
|
||||
msgstr "Source"
|
||||
|
||||
#: init.lua:198
|
||||
msgid ""
|
||||
"A natural spring that generates an endless stream of water source blocks"
|
||||
msgstr ""
|
||||
|
||||
#: init.lua:199
|
||||
msgid ""
|
||||
"Generates one source block of water directly on top of itself once per "
|
||||
"second, provided the space is clear. If this natural spring is dug out the "
|
||||
"flow stops and it is turned into ordinary cobble."
|
||||
msgstr ""
|
|
@ -1,37 +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-12 12:55-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:141
|
||||
msgid "Damp Clay"
|
||||
msgstr ""
|
||||
|
||||
#: init.lua:197
|
||||
msgid "Spring"
|
||||
msgstr ""
|
||||
|
||||
#: init.lua:198
|
||||
msgid ""
|
||||
"A natural spring that generates an endless stream of water source blocks"
|
||||
msgstr ""
|
||||
|
||||
#: init.lua:199
|
||||
msgid ""
|
||||
"Generates one source block of water directly on top of itself once per "
|
||||
"second, provided the space is clear. If this natural spring is dug out the "
|
||||
"flow stops and it is turned into ordinary cobble."
|
||||
msgstr ""
|
|
@ -0,0 +1,4 @@
|
|||
A natural spring that generates an endless stream of water source blocks=
|
||||
Damp Clay=
|
||||
Generates one source block of water directly on top of itself once per second, provided the space is clear. If this natural spring is dug out the flow stops and it is turned into ordinary cobble.=
|
||||
Spring=
|
Loading…
Reference in New Issue