From 3c4c746d5413fd6ec7d80e92dfe454146d178e1d Mon Sep 17 00:00:00 2001 From: Martin Wimpress Date: Sun, 12 Jan 2025 19:05:36 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20add=20L=C3=96VE=20filesystem=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add hasLove() to robustly detect LÖVE runtime - Update loadFile() to handle LÖVE filesystem - Add explicit error handling for file loading - Add type checking for returned data - Fix luacheck warnings for love global --- README.md | 5 ++++- smiti18n/init.lua | 37 ++++++++++++++++++++++++++++--- spec/i18n_spec.lua | 49 ++++++++++++++++++++++++++++++++++++++++- spec/invalid_return.lua | 1 + 4 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 spec/invalid_return.lua diff --git a/README.md b/README.md index 1a07fee..d4f9640 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,14 @@ It provides an intuitive API for managing translations, with support for: - Multiple locale fallbacks - Array-based translations - File-based translation loading +- Seamless LÖVE game engine integration for filesystem paths ### Requirements -- Lua 5.1+ or LuaJIT +- Lua 5.1-5.4 or LuaJIT 2.0-2.1 - LÖVE 11.0+ (*optional*) +### Quick example + Here's a quick example: ```lua diff --git a/smiti18n/init.lua b/smiti18n/init.lua index b594206..c13e2e7 100644 --- a/smiti18n/init.lua +++ b/smiti18n/init.lua @@ -1,3 +1,4 @@ +-- luacheck: globals love local unpack = unpack or table.unpack -- lua 5.2 compat local i18n = {} @@ -28,6 +29,11 @@ local function dotSplit(str) return fields, length end +local function hasLove() + local success, loveEngine = pcall(function() return love end) + return success and type(loveEngine) == 'table' and type(loveEngine.filesystem) == 'table' +end + local function isPluralTable(t) return type(t) == 'table' and type(t.other) == 'string' end @@ -235,10 +241,35 @@ function i18n.load(data) end function i18n.loadFile(path) - local chunk = assert(loadfile(path)) - local data = chunk() + local data + if hasLove() then + -- LÖVE filesystem handling + local loveEngine = love -- store reference to avoid luacheck warning + local contents, readErr = loveEngine.filesystem.read(path) + if not contents then + error("Could not load i18n file: " .. tostring(readErr)) + end + -- Load string as Lua code - use loadstring for 5.1, load for 5.2+ + local chunk, parseErr = (loadstring or load)(contents, path) + if not chunk then + error("Could not parse i18n file: " .. tostring(parseErr)) + end + data = chunk() + else + -- Standard Lua file handling + local chunk, err = loadfile(path) + if not chunk then + error("Could not load i18n file: " .. tostring(err)) + end + data = chunk() + end + + if type(data) ~= 'table' then + error("i18n file must return a table") + end + i18n.load(data) -end + end setmetatable(i18n, {__call = function(_, ...) return i18n.translate(...) end}) diff --git a/spec/i18n_spec.lua b/spec/i18n_spec.lua index 2c0d72d..087d2bc 100644 --- a/spec/i18n_spec.lua +++ b/spec/i18n_spec.lua @@ -155,13 +155,60 @@ describe('i18n', function() end) describe('loadFile', function() - it("Loads a bunch of stuff", function() + after_each(function() + _G.love = nil + i18n.reset() + end) + + it("loads a bunch of stuff", function() i18n.loadFile('spec/en.lua') assert.equal('Hello!', i18n('hello')) local balance = i18n('balance', {value = 0}) assert.equal('Your account balance is 0.', balance) assert.same({"one", "two", "three"}, i18n('array')) end) + + it('uses LÖVE filesystem when available', function() + _G.love = { + filesystem = { + read = function(path) + if path == 'test.lua' then + return [[return { en = { test = "LÖVE File" } }]] + end + return nil, "File not found" + end + } + } + + i18n.loadFile('test.lua') + assert.equal('LÖVE File', i18n('test')) + end) + + it('falls back to standard Lua IO when love has no filesystem', function() + _G.love = {} + i18n.loadFile('spec/en.lua') + assert.equal('Hello!', i18n('hello')) + end) + + it('errors when file returns non-table', function() + assert.error_matches(function() + i18n.loadFile('spec/invalid_return.lua') + end, "i18n file must return a table") + end) + + it('errors when LÖVE file returns non-table', function() + _G.love = { + filesystem = { + read = function(path) + return "return 123" + end + } + } + + assert.error_matches(function() + i18n.loadFile('test.lua') + end, "i18n file must return a table") + end) end) describe('arrays', function() diff --git a/spec/invalid_return.lua b/spec/invalid_return.lua new file mode 100644 index 0000000..036f9b4 --- /dev/null +++ b/spec/invalid_return.lua @@ -0,0 +1 @@ +return 123 -- Returns a number instead of a table for testing error case