Skip to content

Commit cb11b85

Browse files
authored
Merge pull request #14 from alerque/message-access
Add idomatic Lua access to Message from table properties
2 parents eab38ca + 2d105fb commit cb11b85

File tree

4 files changed

+100
-19
lines changed

4 files changed

+100
-19
lines changed

README.md

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,32 @@ Initialized project with some boiler plate Lua aparatus.
4949
Lua code `demo.lua`:
5050

5151
```lua
52+
-- Import and start a new instance
5253
local FluentBundle = require("fluent")
53-
local en = FluentBundle("en-US")
54-
en:add_messages({
55-
"foo = bar",
56-
"hello = Hello { $name }!"
57-
})
58-
print(en:format("foo"))
59-
print(en:format("hello", { name = "World" }))
54+
local bundle = FluentBundle()
55+
56+
-- Load some messages (can be a string or table of strings)
57+
bundle:add_messages([[
58+
foo = bar
59+
hello = Hello { $name }!
60+
]])
61+
62+
-- Access methods like other Fluent implementations
63+
print(bundle:format("foo"))
64+
print(bundle:format("hello", { name = "World" }))
65+
66+
-- Alternate idomatic Lua access methods
67+
print(bundle["foo"]) -- access property, implicit cast to string, cannot pass parammeters
68+
print(bundle.hello({ name = "World" })) -- access as property is callable, parameters passed to format()
6069
```
6170

6271
Output of `lua demo.lua`:
6372

6473
```txt
6574
bar
6675
Hello World!
76+
bar
77+
Hello World!
6778
```
6879

6980
## Alternative(s)

fluent/init.lua

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,25 @@ local FluentBundle = class({
1111
syntax = FluentSyntax(),
1212

1313
_init = function (self, locale)
14-
self.locale = locale
14+
self.locale = locale or "und"
15+
self.locales = {}
16+
-- Penlight bug #307, should be — self:catch(self.get_message)
17+
self:catch(function(_, k) return self:get_message(k) end)
1518
end,
1619

17-
add_messages = function (self, input)
20+
get_message = function (self, identifier)
21+
local locale = rawget(self, "locale")
22+
local locales = rawget(self, "locales")
23+
local default = rawget(locales, locale)
24+
-- TODO iterate over fallback locales if not found in default
25+
return default and default[identifier] or nil
26+
end,
27+
28+
add_messages = function (self, input, locale)
1829
if type(input) == "string" then input = { input } end
1930
local resources = tablex.imap(function (v) return self.syntax:parsestring(v) end, input)
2031
local resource = tablex.reduce('+', resources)
21-
self.locales[self.locale] = resource
32+
self.locales[locale or self.locale] = resource
2233
end,
2334

2435
format = function (self, identifier, parameters)

fluent/resource.lua

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ local FluentNode = class({
5555

5656
attach = function (self, node)
5757
return node and type(node.__mul) == "function" and self * node
58+
end,
59+
60+
__call = function (self, ...)
61+
return self:format(...)
62+
end,
63+
64+
__tostring = function (self)
65+
return self:format({})
66+
end,
67+
68+
__concat = function (a, b)
69+
return tostring(a) .. tostring(b)
5870
end
5971

6072
})
@@ -86,6 +98,11 @@ node_types.Message = class({
8698
_init = function (self, node)
8799
self.attributes = {}
88100
self:super(node)
101+
-- Penlight bug #307, should be — self:catch(self.get_attribute)
102+
self:catch(function(_, k) return self:get_attribute(k) end)
103+
end,
104+
get_attribute = function(self, attribute)
105+
return self.index[attribute] and self.attributes[self.index[attribute]] or nil
89106
end,
90107
format = function (self, parameters)
91108
return self.value:format(parameters)
@@ -298,6 +315,9 @@ node_types.Attribute = class({
298315
self.value = node
299316
return self
300317
end
318+
end,
319+
format = function (self, parameters)
320+
return self.value:format(parameters)
301321
end
302322
})
303323

@@ -350,7 +370,8 @@ local FluentResource = class({
350370
end
351371
end
352372
flush()
353-
-- self:catch(function (self, identifier) return self:get_message(identifier) end)
373+
-- Penlight bug #307, should be — self:catch(self.get_message)
374+
self:catch(function(_, k) return self:get_message(k) end)
354375
end,
355376

356377
insert = function (self, node)
@@ -361,15 +382,12 @@ local FluentResource = class({
361382
end,
362383

363384
get_message = function (self, identifier)
385+
local key = rawget(self.index, string.match(identifier, "^(%a[-_%a%d]+)"))
386+
if not key then return end
387+
local entry = rawget(self, "body")[key]
388+
if not entry then return end
364389
local attr = string.match(identifier, "%.([(%a[-_%a%d]+)$")
365-
local id = string.match(identifier, "^(%a[-_%a%d]+)")
366-
if not self.index[id] then error("No such entry") end
367-
local entry = self.body[self.index[id]]
368-
if attr then
369-
return entry.attributes[entry.index[attr]].value
370-
else
371-
return entry.value
372-
end
390+
return attr and entry.attributes[entry.index[attr]] or entry
373391
end,
374392

375393
dump_ast = function (self)

spec/fluent_spec.lua

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,47 @@ describe('fluent.bundle', function ()
4646
assert.equals("qux", en:format("foo.baz"))
4747
end)
4848

49+
describe('messages', function ()
50+
local en = FluentBundle("en-US")
51+
en:add_messages("hi = Hello { $name }!\nfoo = bar\nbar = baz\n .bax = qux")
52+
53+
it('can be accessed as properties', function ()
54+
assert.same("bar", en.foo:format())
55+
assert.same("bar", en["foo"]:format())
56+
assert.same("baz", en.bar:format())
57+
assert.same("baz", en["bar"]:format())
58+
end)
59+
60+
it('attributes can be accessed as properties', function ()
61+
assert.same("qux", en["bar.bax"]())
62+
assert.same("qux", en.bar["bax"]())
63+
assert.same("qux", en.bar.bax())
64+
end)
65+
66+
it('can be called', function ()
67+
assert.same("bar", en.foo())
68+
assert.same("bar", en["foo"]())
69+
assert.same("baz", en.bar())
70+
assert.same("baz", en["bar"]())
71+
end)
72+
73+
it('can be called with parameters', function ()
74+
assert.same("Hello World!", en.hi({name = "World"}))
75+
assert.same("Hello World!", en["hi"]({name = "World"}))
76+
assert.same("Hello World!", en["hi"]:format({name = "World"}))
77+
end)
78+
79+
it('can be cast to strings', function ()
80+
assert.same("baz", tostring(en.bar))
81+
assert.same("bar", tostring(en["foo"]))
82+
assert.same("xbar", "x" .. en.foo)
83+
assert.same("xbaz", "x" .. en["bar"])
84+
assert.same("barx", en.foo .. "x")
85+
assert.same("bazx", en["bar"] .. "x")
86+
end)
87+
88+
end)
89+
4990
it('should keep locale instances separate', function ()
5091
local en = FluentBundle("en-US")
5192
local tr = FluentBundle("tr-TR")

0 commit comments

Comments
 (0)