Skip to content

Commit

Permalink
More work on Lua and localization.
Browse files Browse the repository at this point in the history
  • Loading branch information
icculus committed Dec 3, 2006
1 parent 62fe8e4 commit b1d0b88
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 72 deletions.
2 changes: 0 additions & 2 deletions lua/config.lua
Expand Up @@ -60,7 +60,5 @@ MojoSetup.Install
};
};

MojoSetup.dumptable("MojoSetup.installs", MojoSetup.installs);

-- end of config.lua ...

61 changes: 52 additions & 9 deletions lua/mojosetup_init.lua
Expand Up @@ -5,16 +5,56 @@
-- what the Lua runtime claims for itself.
--
-- This file is loaded and executed at MojoSetup startup. Lua is initialized,
-- the MojoSetup table is created and has its CFunctions inserted, then this
-- code executes to do the heavy lifting. Localization is not ready yet.
-- the MojoSetup table is created and has some initial CFunctions and such
-- inserted. The localization script runs, and then this code executes to do
-- the heavy lifting. All Lua state should be sane for the rest of the app
-- once this script successfully completes.

-- This table gets filled by the config file. Just create an empty one for now.
MojoSetup.installs = {}

-- Our namespace for this API...this is filled in with the rest of this file.
MojoSetup.schema = {}
-- Build the translations table from the localizations table supplied in
-- localizations.lua...
if type(MojoSetup.localization) ~= "table" then
MojoSetup.localization = nil
end

if MojoSetup.localization ~= nil then
MojoSetup.translations = {}
local locale = MojoSetup.locale
local lang = string.gsub(locale, "_%w+", "", 1) -- make "en_US" into "en"
for k,v in pairs(MojoSetup.localization) do

if type(v) == "table" then
if v[locale] ~= nil then
MojoSetup.translations[k] = v[locale]
elseif v[lang] ~= nil then
MojoSetup.translations[k] = v[lang]
end
end
end

-- Delete the table if there's no actual useful translations for this run.
if (#MojoSetup.translations == 0) then
MojoSetup.translations = nil
end

-- This is eligible for garbage collection now. We're done with it.
MojoSetup.localization = nil
end

-- Handy for debugging.

function MojoSetup.translate(str)
if MojoSetup.translations ~= nil then
if MojoSetup.translations[str] ~= nil then
return MojoSetup.translations[str]
end
end
return str
end


-- This is handy for debugging.
function MojoSetup.dumptable(tabname, tab, depth)
if depth == nil then depth = 1 end
if tabname ~= nil then
Expand All @@ -26,13 +66,13 @@ function MojoSetup.dumptable(tabname, tab, depth)
depthstr = depthstr .. " "
end

for k in pairs(tab) do
if type(tab[k]) == "table" then
for k,v in pairs(tab) do
if type(v) == "table" then
print(depthstr .. k .. " = {")
MojoSetup.dumptable(nil, tab[k], depth + 1)
MojoSetup.dumptable(nil, v, depth + 1)
print(depthstr .. "}")
else
print(depthstr .. k .. " = " .. tostring(tab[k]))
print(depthstr .. k .. " = " .. tostring(v))
end
end

Expand All @@ -41,6 +81,9 @@ function MojoSetup.dumptable(tabname, tab, depth)
end
end

-- Our namespace for this API...this is filled in with the rest of this file.
MojoSetup.schema = {}

function MojoSetup.schema.assert(test, fnname, elem, error)
assert(test, fnname .. "::" .. elem .. " -- " .. error .. ".")
end
Expand Down
13 changes: 9 additions & 4 deletions lua/translations.lua
@@ -1,14 +1,19 @@
-- NOTE: If you care about Unicode, this file _MUST_ be UTF-8 encoded!
-- NOTE: If you care about Unicode or ASCII chars above 127, this file _MUST_
-- be UTF-8 encoded! If you think you're using a certain high-ascii codepage,
-- you're wrong!
--
-- Most of the MojoSetup table isn't set up when this code is run, so you
-- Most of the MojoSetup table isn't set up when this code is run, so you
-- shouldn't rely on any of it. For most purposes, you should treat this
-- file more like a data description language and less like a turing-complete
-- scripting language.
--
-- You should leave the existing strings here. They aren't hurting anything,
-- and most are used by MojoSetup itself. Add your own, though.
--
-- The table you create here goes away shortly after creation; you should
-- call MojoSetup.translate() to localize strings in your config file.

MojoSetup.translations = {
MojoSetup.localization = {
["README.txt"] = {
es = "README_spanish.txt";
l33t = "README_l33t.txt";
Expand All @@ -25,5 +30,5 @@ MojoSetup.translations = {
};
}

-- end of translations.lua ...
-- end of localization.lua ...

95 changes: 46 additions & 49 deletions lua_glue.c
@@ -1,4 +1,5 @@
#include "universal.h"
#include "platform.h"
#include "fileio.h"
#include "lua.h"
#include "lauxlib.h"
Expand Down Expand Up @@ -69,32 +70,45 @@ boolean MojoLua_runFile(const char *basefname)
} // MojoLua_runFile


void MojoLua_collectGarbage(void)
{
lua_State *L = luaState;
int pre = 0;
int post = 0;

STUBBED("logging!");
pre = (lua_gc(L, LUA_GCCOUNT, 0) * 1024) + lua_gc(L, LUA_GCCOUNTB, 0);
printf("Collecting garbage (currently using %d bytes).\n", pre);
lua_gc (L, LUA_GCCOLLECT, 0);
printf("Collection finished (took ??? milliseconds).\n"); // !!! FIXME
post = (lua_gc(L, LUA_GCCOUNT, 0) * 1024) + lua_gc(L, LUA_GCCOUNTB, 0);
printf("Now using %d bytes (%d bytes savings).\n", post, pre - post);
} // MojoLua_collectGarbage


// Since localization is kept in Lua tables, I stuck this in the Lua glue.
const char *translate(const char *str)
{
const char *retval = str;
int popcount = 0;

if (lua_checkstack(luaState, 4))
if (!lua_checkstack(luaState, 5))
return str;

lua_getglobal(luaState, MOJOSETUP_NAMESPACE); popcount++;
if (lua_istable(luaState, -1)) // namespace is sane?
{
lua_getglobal(luaState, MOJOSETUP_NAMESPACE); popcount++;
if (lua_istable(luaState, -1)) // namespace is sane?
lua_getfield(luaState, -1, "translate"); popcount++;
if (lua_isfunction(luaState, -1))
{
lua_getfield(luaState, -1, "translations"); popcount++;
if (lua_istable(luaState, -1)) // translation table is sane?
const char *tr = NULL;
lua_pushstring(luaState, str);
lua_call(luaState, 1, 1); // popcount ends up the same...
tr = lua_tostring(luaState, -1);
if (tr != NULL)
{
lua_getfield(luaState, -1, str); popcount++;
if (lua_istable(luaState, -1)) // translation exists at all?
{
const char *tr = NULL;
lua_getfield(luaState, -1, GLocale); popcount++;
tr = lua_tostring(luaState, -1);
if (tr != NULL) // translated for this locale?
{
xstrncpy(scratchbuf_128k, tr, sizeof(scratchbuf_128k));
retval = scratchbuf_128k;
} // if
} // if
xstrncpy(scratchbuf_128k, tr, sizeof(scratchbuf_128k));
retval = scratchbuf_128k;
} // if
} // if
} // if
Expand All @@ -115,34 +129,6 @@ static int MojoLua_panic(lua_State *L)
} // MojoLua_panic


static int MojoLua_translate(lua_State *L)
{
int argc = lua_gettop(L);
int i;
for (i = 1; i <= argc; i++)
{
const char *str = lua_tostring(L, i);
if (str == NULL)
{
lua_pushstring(L, _("Argument not a string in '"
MOJOSETUP_NAMESPACE ".translate'"));
return lua_error(L);
} // if

lua_pushstring(L, translate(str));
} // for

return argc;
} // MojoLua_translate


static int MojoLua_locale(lua_State *L)
{
lua_pushstring(L, GLocale);
return 1;
} // MojoLua_translate


// Sets t[sym]=f, where t is on the top of the Lua stack.
static inline void set_cfunc(lua_State *L, lua_CFunction f, const char *sym)
{
Expand All @@ -151,10 +137,22 @@ static inline void set_cfunc(lua_State *L, lua_CFunction f, const char *sym)
} // set_cfunc


// Sets t[sym]=f, where t is on the top of the Lua stack.
static inline void set_string(lua_State *L, const char *str, const char *sym)
{
lua_pushstring(luaState, str);
lua_setfield(luaState, -2, sym);
} // set_string


boolean MojoLua_initLua(void)
{
char locale[16];
assert(luaState == NULL);

if (!MojoPlatform_locale(locale, sizeof (locale)))
xstrncpy(locale, "???", sizeof (locale));

luaState = luaL_newstate(); // !!! FIXME: define our own allocator?
if (luaState == NULL)
return false;
Expand All @@ -172,13 +170,12 @@ boolean MojoLua_initLua(void)

// Build MojoSetup namespace for Lua to access and fill in C bridges...
lua_newtable(luaState);
// Set up C functions we want to expose to Lua code...
set_cfunc(luaState, MojoLua_translate, "translate");
set_cfunc(luaState, MojoLua_locale, "locale");
// Set up initial C functions, etc we want to expose to Lua code...
set_string(luaState, locale, "locale");
lua_setglobal(luaState, "MojoSetup");

// Set up localization table, if possible.
MojoLua_runFile("translations");
MojoLua_runFile("localization");

// Transfer control to Lua to setup some APIs and state...
if (!MojoLua_runFile("mojosetup_init"))
Expand Down
2 changes: 2 additions & 0 deletions lua_glue.h
Expand Up @@ -20,6 +20,8 @@ void MojoLua_deinitLua(void);
// chunk, as it will call fatal() instead.
boolean MojoLua_runFile(const char *fname);

void MojoLua_collectGarbage(void);

#ifdef __cplusplus
}
#endif
Expand Down
1 change: 0 additions & 1 deletion misc.c
Expand Up @@ -6,7 +6,6 @@
uint8 scratchbuf_128k[128 * 1024];
int GArgc = 0;
char **GArgv = NULL;
char *GLocale = NULL;

int fatal(const char *err)
{
Expand Down
4 changes: 0 additions & 4 deletions mojosetup.c
Expand Up @@ -41,17 +41,13 @@ int MojoSetup_main(int argc, char **argv)
GArgc = argc;
GArgv = argv;

GLocale = xstrdup("es"); // !!! FIXME

if (!initEverything())
return 1;

GGui->msgbox(GGui, "translating...", _("Required for play"));

deinitEverything();

free(GLocale); // !!! FIXME

return 0;
} // MojoSetup_main

Expand Down
6 changes: 6 additions & 0 deletions platform.h
Expand Up @@ -15,6 +15,12 @@ int MojoSetup_main(int argc, char **argv);
// !!! FIXME: is that a good idea?
const char *MojoPlatform_appBinaryPath(void);

// Get the current locale, in the format "xx_YY" where "xx" is the language
// (en, fr, de...) and "_YY" is the country. (_US, _CA, etc). The country
// can be omitted. Don't include encoding, it's always UTF-8 at this time.
// Return true if locale is known, false otherwise.
boolean MojoPlatform_locale(char *buf, size_t len);

#ifdef __cplusplus
}
#endif
Expand Down
19 changes: 19 additions & 0 deletions platform/unix.c
Expand Up @@ -97,5 +97,24 @@ const char *MojoPlatform_appBinaryPath(void)
return retval;
} // MojoPlatform_appBinaryPath


// This implementation is a bit naive.
boolean MojoPlatform_locale(char *buf, size_t len)
{
boolean retval = false;
const char *envr = getenv("LANG");
if (envr != NULL)
{
char *ptr = NULL;
xstrncpy(buf, envr, len);
ptr = strchr(buf, '.'); // chop off encoding if explicitly listed.
if (ptr != NULL)
*ptr = '\0';
retval = true;
} // if

return retval;
} // MojoPlatform_locale

// end of unix.c ...

3 changes: 0 additions & 3 deletions universal.h
Expand Up @@ -36,9 +36,6 @@ typedef int boolean;
extern int GArgc;
extern char **GArgv;

// The current locale.
extern char *GLocale;

// Static, non-stack memory for scratch work...not thread safe!
// !!! FIXME: maybe lose this.
extern uint8 scratchbuf_128k[128 * 1024];
Expand Down

0 comments on commit b1d0b88

Please sign in to comment.