diff --git a/mods/beds/depends.txt b/mods/beds/depends.txt index 470ec30b..8c4c21f4 100644 --- a/mods/beds/depends.txt +++ b/mods/beds/depends.txt @@ -1,2 +1,3 @@ default wool +intllib? diff --git a/mods/beds/functions.lua b/mods/beds/functions.lua index 85f6dc8b..f67390a5 100644 --- a/mods/beds/functions.lua +++ b/mods/beds/functions.lua @@ -36,7 +36,7 @@ local function check_in_beds(players) end end - return true + return #players > 0 end local function lay_down(player, pos, bed_pos, state, skip) @@ -99,13 +99,13 @@ local function update_formspecs(finished) if finished then form_n = beds.formspec .. - S("label[2.7,11; Good morning.]") + "label[2.7,11; " .. S("Good morning.") .. "]" else form_n = beds.formspec .. "label[2.2,11;"..tostring(player_in_bed)..S(" of ")..tostring(ges)..S(" players are in bed]") if is_majority then form_n = form_n .. - S("button_exit[2,8;4,0.75;force;Force night skip]") + "button_exit[2,8;4,0.75;force;" .. S("Force night skip") .. "]" end end diff --git a/mods/beds/init.lua b/mods/beds/init.lua index 34b1d00f..468c430b 100644 --- a/mods/beds/init.lua +++ b/mods/beds/init.lua @@ -13,7 +13,7 @@ beds.intllib = S beds.formspec = "size[8,15;true]".. "bgcolor[#080808BB; true]".. - S("button_exit[2,12;4,0.75;leave;Leave Bed]") + "button_exit[2,12;4,0.75;leave;" .. S("Leave Bed") .. "]" local modpath = minetest.get_modpath("beds") diff --git a/mods/beds/locale/es.txt b/mods/beds/locale/es.txt index e1c1d1ff..8a3b43df 100755 --- a/mods/beds/locale/es.txt +++ b/mods/beds/locale/es.txt @@ -2,12 +2,12 @@ Fancy Bed = Cama elegante Simple Bed = Cama simple -#functions +#functions.lua of = de players are in bed] = jugadores están en cama] -label[2.7,11; Good morning.] = label[2.7,11; Buen día.] -button_exit[2,8;4,0.75;force;Force night skip] = button_exit[2,8;4,0.75;force;Forzar saltar noche] +Good morning. = Buen día. +Force night skip = Forzar saltar noche You can only sleep at night. = Solo es posible dormir por la noche. #init.lua -button_exit[2,12;4,0.75;leave;Leave Bed] = button_exit[2,12;4,0.75;leave;Dejar la cama] +Leave Bed = Dejar la cama diff --git a/mods/boats/depends.txt b/mods/boats/depends.txt index 4ad96d51..9207dab8 100644 --- a/mods/boats/depends.txt +++ b/mods/boats/depends.txt @@ -1 +1,2 @@ default +intllib? diff --git a/mods/bones/depends.txt b/mods/bones/depends.txt index 4ad96d51..9207dab8 100644 --- a/mods/bones/depends.txt +++ b/mods/bones/depends.txt @@ -1 +1,2 @@ default +intllib? diff --git a/mods/bucket/depends.txt b/mods/bucket/depends.txt index 3a7daa1d..c48fe0d0 100644 --- a/mods/bucket/depends.txt +++ b/mods/bucket/depends.txt @@ -1,2 +1,3 @@ default +intllib? diff --git a/mods/default/depends.txt b/mods/default/depends.txt new file mode 100755 index 00000000..77e8d97c --- /dev/null +++ b/mods/default/depends.txt @@ -0,0 +1 @@ +intllib? diff --git a/mods/default/locale/es.txt b/mods/default/locale/es.txt index 0c1e36b7..78709939 100755 --- a/mods/default/locale/es.txt +++ b/mods/default/locale/es.txt @@ -1,5 +1,3 @@ -# translation by Adimgar - #craftitems.lua Stick = Vara Paper = Papel diff --git a/mods/doors/depends.txt b/mods/doors/depends.txt index 5e28beeb..8c44a348 100644 --- a/mods/doors/depends.txt +++ b/mods/doors/depends.txt @@ -1,2 +1,3 @@ default screwdriver? +intllib? diff --git a/mods/dye/depends.txt b/mods/dye/depends.txt index e69de29b..77e8d97c 100644 --- a/mods/dye/depends.txt +++ b/mods/dye/depends.txt @@ -0,0 +1 @@ +intllib? diff --git a/mods/farming/depends.txt b/mods/farming/depends.txt index 470ec30b..8c4c21f4 100644 --- a/mods/farming/depends.txt +++ b/mods/farming/depends.txt @@ -1,2 +1,3 @@ default wool +intllib? diff --git a/mods/fire/depends.txt b/mods/fire/depends.txt new file mode 100755 index 00000000..77e8d97c --- /dev/null +++ b/mods/fire/depends.txt @@ -0,0 +1 @@ +intllib? diff --git a/mods/flowers/depends.txt b/mods/flowers/depends.txt index 4ad96d51..9207dab8 100644 --- a/mods/flowers/depends.txt +++ b/mods/flowers/depends.txt @@ -1 +1,2 @@ default +intllib? diff --git a/mods/give_initial_stuff/depends.txt b/mods/give_initial_stuff/depends.txt index 3a7daa1d..9207dab8 100644 --- a/mods/give_initial_stuff/depends.txt +++ b/mods/give_initial_stuff/depends.txt @@ -1,2 +1,2 @@ default - +intllib? diff --git a/mods/intllib/README.txt b/mods/intllib/README.txt new file mode 100644 index 00000000..4fc43cd9 --- /dev/null +++ b/mods/intllib/README.txt @@ -0,0 +1,83 @@ + +Internationalization Lib for Minetest +By Diego Martínez (a.k.a. "Kaeza"). +Released as WTFPL. + +This mod is an attempt at providing internationalization support for mods +(something Minetest currently lacks). + +How do I use it? +In order to enable it for your mod, copy the following code snippet and paste +it at the beginning of your source file(s): + + -- Boilerplate to support localized strings if intllib mod is installed. + local S + if minetest.get_modpath("intllib") then + S = intllib.Getter() + else + -- If you don't use insertions (@1, @2, etc) you can use this: + S = function(s) return s end + + -- If you use insertions, but not insertion escapes this will work: + S = function(s,a,...)a={a,...}return s:gsub("@(%d+)",function(n)return a[tonumber(n)]end)end + + -- Use this if you require full functionality + S = function(s,a,...)if a==nil then return s end a={a,...}return s:gsub("(@?)@(%(?)(%d+)(%)?)",function(e,o,n,c)if e==""then return a[tonumber(n)]..(o==""and c or"")else return"@"..o..n..c end end) end + end + +You will also need to optionally depend on intllib, to do so add "intllib?" to +a empty line in your depends.txt. Also note that if intllib is not installed, +the S() function is defined so it returns the string unchanged. This is done +so you don't have to sprinkle tons of 'if's (or similar constructs) to check +if the lib is actually installed. + +Next, for each "translatable" string in your sources, use the S() function +(defined in the snippet) to return the translated string. For example: + + minetest.register_node("mymod:mynode", { + description = S("My Fabulous Node"), + <...> + }) + +Then, you create a `locale' directory inside your mod directory, with files +named after the two-letter ISO Language Code of the languages you want to +support. Here's an example for a Spanish locale file (`es.txt'): + + # Lines beginning with a pound sign are comments and are effectively ignored + # by the reader. Note that comments only span until the end of the line; + # there's no support for multiline comments. + Hello, World! = Hola, Mundo! + String with\nnewlines = Cadena con\nsaltos de linea + String with an \= equals sign = Cadena con un signo de \= igualdad + +Since there's currently no portable way to detect the language, this library +tries several alternatives, and uses the first one found: + - `language' setting in `minetest.conf' + - `LANG' environment variable (this is always set on Unix-like OSes). + - Default of "en". +Note that in any case only up to the first two characters are used, so for +example, the settings "de_DE.UTF-8", "de_DE", and "de" are all equal. +Windows users have no `LANG' environment variable by default. To add it, do +the following: + - Click Start->Settings->Control Panel. + - Start the "System" applet. + - Click on the "Advanced" tab. + - Click on the "Environment variables" button + - Click "New". + - Type "LANG" (without quotes) as name and the language code as value. + - Click OK until all dialogs are closed. +Alternatively for all platforms, if you don't want to modify system settings, +you may add the following line to your `minetest.conf' file: + language = + +Also note that there are some problems with using accented, and in general +non-latin characters in strings. Until a fix is found, please limit yourself +to using only US-ASCII characters. + +Thanks for reading up to this point. +Should you have any comments/suggestions, please post them in the forum topic. + +Let there be translated texts! :P +-- +Yours Truly, +Kaeza diff --git a/mods/intllib/init.lua b/mods/intllib/init.lua new file mode 100644 index 00000000..21d4e024 --- /dev/null +++ b/mods/intllib/init.lua @@ -0,0 +1,74 @@ + +-- Old multi-load method compatibility +if rawget(_G, "intllib") then return end + +intllib = { + getters = {}, + strings = {}, +} + + +local MP = minetest.get_modpath("intllib") + +dofile(MP.."/lib.lua") + + +local LANG = minetest.setting_get("language") +if not (LANG and (LANG ~= "")) then LANG = os.getenv("LANG") end +if not (LANG and (LANG ~= "")) then LANG = "en" end +LANG = LANG:sub(1, 2) + + +local INS_CHAR = intllib.INSERTION_CHAR +local insertion_pattern = "("..INS_CHAR.."?)"..INS_CHAR.."(%(?)(%d+)(%)?)" + +local function make_getter(msgstrs) + return function(s, ...) + local str + if msgstrs then + str = msgstrs[s] + end + if not str or str == "" then + str = s + end + if select("#", ...) == 0 then + return str + end + local args = {...} + str = str:gsub(insertion_pattern, function(escape, open, num, close) + if escape == "" then + local replacement = tostring(args[tonumber(num)]) + if open == "" then + replacement = replacement..close + end + return replacement + else + return INS_CHAR..open..num..close + end + end) + return str + end +end + + +function intllib.Getter(modname) + modname = modname or minetest.get_current_modname() + if not intllib.getters[modname] then + local msgstr = intllib.get_strings(modname) + intllib.getters[modname] = make_getter(msgstr) + end + return intllib.getters[modname] +end + + +function intllib.get_strings(modname) + modname = modname or minetest.get_current_modname() + local msgstr = intllib.strings[modname] + if not msgstr then + local modpath = minetest.get_modpath(modname) + msgstr = intllib.load_strings(modpath.."/locale/"..LANG..".txt") + intllib.strings[modname] = msgstr + end + return msgstr or nil +end + diff --git a/mods/intllib/intllib.lua b/mods/intllib/intllib.lua new file mode 100644 index 00000000..adb0f886 --- /dev/null +++ b/mods/intllib/intllib.lua @@ -0,0 +1,3 @@ +-- Support for the old multi-load method +dofile(minetest.get_modpath("intllib").."/init.lua") + diff --git a/mods/intllib/lib.lua b/mods/intllib/lib.lua new file mode 100644 index 00000000..2349de46 --- /dev/null +++ b/mods/intllib/lib.lua @@ -0,0 +1,63 @@ + +intllib = intllib or {} + +local INS_CHAR = "@" +intllib.INSERTION_CHAR = INS_CHAR + +local escapes = { + ["\\"] = "\\", + ["n"] = "\n", + [INS_CHAR] = INS_CHAR..INS_CHAR, +} + +local function unescape(str) + local parts = {} + local n = 1 + local function add(s) + parts[n] = s + n = n + 1 + end + + local start = 1 + while true do + local pos = str:find("\\", start, true) + if pos then + add(str:sub(start, pos - 1)) + else + add(str:sub(start)) + break + end + local c = str:sub(pos + 1, pos + 1) + add(escapes[c] or c) + start = pos + 2 + end + return table.concat(parts) +end + +local function find_eq(s) + for slashes, pos in s:gmatch("([\\]*)=()") do + if (slashes:len() % 2) == 0 then + return pos - 1 + end + end +end + +function intllib.load_strings(filename) + local file, err = io.open(filename, "r") + if not file then + return nil + end + local strings = {} + for line in file:lines() do + line = line:trim() + if line ~= "" and line:sub(1, 1) ~= "#" then + local pos = find_eq(line) + if pos then + local msgid = unescape(line:sub(1, pos - 1):trim()) + strings[msgid] = unescape(line:sub(pos + 1):trim()) + end + end + end + file:close() + return strings +end diff --git a/mods/intllib/tools/findtext.lua b/mods/intllib/tools/findtext.lua new file mode 100755 index 00000000..b6360cb6 --- /dev/null +++ b/mods/intllib/tools/findtext.lua @@ -0,0 +1,142 @@ +#! /usr/bin/env lua + +local me = arg[0]:gsub(".*[/\\](.*)$", "%1") + +local function err(fmt, ...) + io.stderr:write(("%s: %s\n"):format(me, fmt:format(...))) + os.exit(1) +end + +local output +local inputs = { } +local lang +local author + +local i = 1 + +local function usage() + print([[ +Usage: ]]..me..[[ [OPTIONS] FILE... + +Extract translatable strings from the given FILE(s). + +Available options: + -h,--help Show this help screen and exit. + -o,--output X Set output file (default: stdout). + -a,--author X Set author. + -l,--lang X Set language name. +]]) + os.exit(0) +end + +while i <= #arg do + local a = arg[i] + if (a == "-h") or (a == "--help") then + usage() + elseif (a == "-o") or (a == "--output") then + i = i + 1 + if i > #arg then + err("missing required argument to `%s'", a) + end + output = arg[i] + elseif (a == "-a") or (a == "--author") then + i = i + 1 + if i > #arg then + err("missing required argument to `%s'", a) + end + author = arg[i] + elseif (a == "-l") or (a == "--lang") then + i = i + 1 + if i > #arg then + err("missing required argument to `%s'", a) + end + lang = arg[i] + elseif a:sub(1, 1) ~= "-" then + table.insert(inputs, a) + else + err("unrecognized option `%s'", a) + end + i = i + 1 +end + +if #inputs == 0 then + err("no input files") +end + +local outfile = io.stdout + +local function printf(fmt, ...) + outfile:write(fmt:format(...)) +end + +if output then + local e + outfile, e = io.open(output, "w") + if not outfile then + err("error opening file for writing: %s", e) + end +end + +if author or lang then + outfile:write("\n") +end + +if lang then + printf("# Language: %s\n", lang) +end + +if author then + printf("# Author: %s\n", author) +end + +if author or lang then + outfile:write("\n") +end + +local escapes = { + ["\n"] = "\\n", + ["="] = "\\=", + ["\\"] = "\\\\", +} + +local function escape(s) + return s:gsub("[\\\n=]", escapes) +end + +local messages = { } + +for _, file in ipairs(inputs) do + local infile, e = io.open(file, "r") + if infile then + for line in infile:lines() do + for s in line:gmatch('S%("([^"]*)"') do + table.insert(messages, s) + end + end + infile:close() + else + io.stderr:write(("%s: WARNING: error opening file: %s\n"):format(me, e)) + end +end + +table.sort(messages) + +local last_msg + +for i, msg in ipairs(messages) do + if msg ~= last_msg then + printf("%s =\n", escape(msg)) + end + last_msg = msg +end + +if output then + outfile:close() +end + +--[[ +TESTS: +S("foo") S("bar") +S("bar") +S("foo") +]] diff --git a/mods/intllib/tools/updatetext.lua b/mods/intllib/tools/updatetext.lua new file mode 100644 index 00000000..00f9bf68 --- /dev/null +++ b/mods/intllib/tools/updatetext.lua @@ -0,0 +1,141 @@ +#! /usr/bin/env lua + +local basedir = "" +if arg[0]:find("[/\\]") then + basedir = arg[0]:gsub("(.*[/\\]).*$", "%1"):gsub("\\", "/") +end +if basedir == "" then basedir = "./" end + +-- Required by load_strings() +function string.trim(s) + return s:gsub("^%s*(.-)%s*$", "%1") +end + +dofile(basedir.."/../lib.lua") + +local me = arg[0]:gsub(".*[/\\](.*)$", "%1") + +local function err(fmt, ...) + io.stderr:write(("%s: %s\n"):format(me, fmt:format(...))) + os.exit(1) +end + +local template +local catalogs = { } + +local function usage() + print([[ +Usage: ]]..me..[[ [OPTIONS] TEMPLATE CATALOG... + +Update a catalog with new strings from a template. + +Available options: + -h,--help Show this help screen and exit. + -o,--output X Set output file (default: stdout). + +Messages in the template that are not on the catalog are added to the +catalog at the end. + +This tool also checks messages that are in the catalog but not in the +template, and reports such lines. It's up to the user to remove such +lines, if so desired. +]]) + os.exit(0) +end + +local i = 1 + +while i <= #arg do + local a = arg[i] + if (a == "-h") or (a == "--help") then + usage() + elseif (a == "-o") or (a == "--output") then + i = i + 1 + if i > #arg then + err("missing required argument to `%s'", a) + end + elseif (a == "-c") or (a == "--comment") then + old_msg_mode = "c" + elseif (a == "-d") or (a == "--delete") then + old_msg_mode = "d" + elseif a:sub(1, 1) ~= "-" then + if not template then + template = a + else + table.insert(catalogs, a) + end + else + err("unrecognized option `%s'", a) + end + i = i + 1 +end + +if not template then + err("no template specified") +elseif #catalogs == 0 then + err("no catalogs specified") +end + +local f, e = io.open(template, "r") +if not f then + err("error opening template: %s", e) +end + +local function printf(fmt, ...) + outfile:write(fmt:format(...)) +end + +local escapes = { ["\n"] = "\\n", ["="] = "\\=", ["\\"] = "\\\\", } +local function escape(s) + return s:gsub("[\\\n=]", escapes) +end + +if output then + local e + outfile, e = io.open(output, "w") + if not outfile then + err("error opening file for writing: %s", e) + end +end + +local function printf(fmt, ...) + io.stdout:write(fmt:format(...)) +end + +local template_msgs = intllib.load_strings(template) + +for _, file in ipairs(catalogs) do + print("Processing: "..file) + local catalog_msgs = intllib.load_strings(file) + local dirty_lines = { } + if catalog_msgs then + -- Add new entries from template. + for k in pairs(template_msgs) do + if not catalog_msgs[k] then + print("NEW: "..k) + table.insert(dirty_lines, escape(k).." =") + end + end + -- Check for old messages. + for k, v in pairs(catalog_msgs) do + if not template_msgs[k] then + print("OLD: "..k) + end + end + if #dirty_lines > 0 then + local outf, e = io.open(file, "a+") + if outf then + outf:write("\n") + for _, line in ipairs(dirty_lines) do + outf:write(line) + outf:write("\n") + end + outf:close() + else + io.stderr:write(("%s: WARNING: cannot write: %s\n"):format(me, e)) + end + end + else + io.stderr:write(("%s: WARNING: could not load catalog\n"):format(me)) + end +end diff --git a/mods/screwdriver/depends.txt b/mods/screwdriver/depends.txt new file mode 100755 index 00000000..77e8d97c --- /dev/null +++ b/mods/screwdriver/depends.txt @@ -0,0 +1 @@ +intllib? diff --git a/mods/sethome/depends.txt b/mods/sethome/depends.txt new file mode 100755 index 00000000..77e8d97c --- /dev/null +++ b/mods/sethome/depends.txt @@ -0,0 +1 @@ +intllib? diff --git a/mods/stairs/depends.txt b/mods/stairs/depends.txt index 4ad96d51..9207dab8 100644 --- a/mods/stairs/depends.txt +++ b/mods/stairs/depends.txt @@ -1 +1,2 @@ default +intllib? diff --git a/mods/tnt/depends.txt b/mods/tnt/depends.txt index 5ff216f7..37ad568c 100644 --- a/mods/tnt/depends.txt +++ b/mods/tnt/depends.txt @@ -1,3 +1,3 @@ default fire - +intllib? diff --git a/mods/tnt/locale/es.txt b/mods/tnt/locale/es.txt index df940456..b12b7324 100755 --- a/mods/tnt/locale/es.txt +++ b/mods/tnt/locale/es.txt @@ -1,3 +1,3 @@ #init.lua Gun Powder = Pólvora -[TNT] Cargado! +[TNT] Loaded! = [TNT] Cargado! diff --git a/mods/vessels/depends.txt b/mods/vessels/depends.txt index 4ad96d51..9207dab8 100644 --- a/mods/vessels/depends.txt +++ b/mods/vessels/depends.txt @@ -1 +1,2 @@ default +intllib? diff --git a/mods/wool/depends.txt b/mods/wool/depends.txt index 4ad96d51..9207dab8 100644 --- a/mods/wool/depends.txt +++ b/mods/wool/depends.txt @@ -1 +1,2 @@ default +intllib? diff --git a/mods/xpanes/depends.txt b/mods/xpanes/depends.txt index 331d858c..9207dab8 100644 --- a/mods/xpanes/depends.txt +++ b/mods/xpanes/depends.txt @@ -1 +1,2 @@ -default \ No newline at end of file +default +intllib?