luci-base: add support for plural translations and contexts in Lua api
[project/luci.git] / modules / luci-base / src / template_lualib.c
1 /*
2 * LuCI Template - Lua binding
3 *
4 * Copyright (C) 2009 Jo-Philipp Wich <jow@openwrt.org>
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include "template_lualib.h"
20
21 static int template_L_do_parse(lua_State *L, struct template_parser *parser, const char *chunkname)
22 {
23 int lua_status, rv;
24
25 if (!parser)
26 {
27 lua_pushnil(L);
28 lua_pushinteger(L, errno);
29 lua_pushstring(L, strerror(errno));
30 return 3;
31 }
32
33 lua_status = lua_load(L, template_reader, parser, chunkname);
34
35 if (lua_status == 0)
36 rv = 1;
37 else
38 rv = template_error(L, parser);
39
40 template_close(parser);
41
42 return rv;
43 }
44
45 int template_L_parse(lua_State *L)
46 {
47 const char *file = luaL_checkstring(L, 1);
48 struct template_parser *parser = template_open(file);
49
50 return template_L_do_parse(L, parser, file);
51 }
52
53 int template_L_parse_string(lua_State *L)
54 {
55 size_t len;
56 const char *str = luaL_checklstring(L, 1, &len);
57 struct template_parser *parser = template_string(str, len);
58
59 return template_L_do_parse(L, parser, "[string]");
60 }
61
62 int template_L_utf8(lua_State *L)
63 {
64 size_t len = 0;
65 const char *str = luaL_checklstring(L, 1, &len);
66 char *res = utf8(str, len);
67
68 if (res != NULL)
69 {
70 lua_pushstring(L, res);
71 free(res);
72
73 return 1;
74 }
75
76 return 0;
77 }
78
79 int template_L_pcdata(lua_State *L)
80 {
81 size_t len = 0;
82 const char *str = luaL_checklstring(L, 1, &len);
83 char *res = pcdata(str, len);
84
85 if (res != NULL)
86 {
87 lua_pushstring(L, res);
88 free(res);
89
90 return 1;
91 }
92
93 return 0;
94 }
95
96 int template_L_striptags(lua_State *L)
97 {
98 size_t len = 0;
99 const char *str = luaL_checklstring(L, 1, &len);
100 char *res = striptags(str, len);
101
102 if (res != NULL)
103 {
104 lua_pushstring(L, res);
105 free(res);
106
107 return 1;
108 }
109
110 return 0;
111 }
112
113 static int template_L_load_catalog(lua_State *L) {
114 const char *lang = luaL_optstring(L, 1, "en");
115 const char *dir = luaL_optstring(L, 2, NULL);
116 lua_pushboolean(L, !lmo_load_catalog(lang, dir));
117 return 1;
118 }
119
120 static int template_L_close_catalog(lua_State *L) {
121 const char *lang = luaL_optstring(L, 1, "en");
122 lmo_close_catalog(lang);
123 return 0;
124 }
125
126 static int template_L_change_catalog(lua_State *L) {
127 const char *lang = luaL_optstring(L, 1, "en");
128 lua_pushboolean(L, !lmo_change_catalog(lang));
129 return 1;
130 }
131
132 static void template_L_get_translations_cb(uint32_t key, const char *val, int len, void *priv) {
133 lua_State *L = priv;
134 char hex[9];
135
136 luaL_checktype(L, 1, LUA_TFUNCTION);
137 snprintf(hex, sizeof(hex), "%08x", key);
138
139 lua_pushvalue(L, 1);
140 lua_pushstring(L, hex);
141 lua_pushlstring(L, val, len);
142 lua_call(L, 2, 0);
143 }
144
145 static int template_L_get_translations(lua_State *L) {
146 lmo_iterate(template_L_get_translations_cb, L);
147 return 0;
148 }
149
150 static int template_L_translate(lua_State *L) {
151 size_t len, ctxlen = 0;
152 char *tr;
153 int trlen;
154 const char *key = luaL_checklstring(L, 1, &len);
155 const char *ctx = luaL_optlstring(L, 2, NULL, &ctxlen);
156
157 switch (lmo_translate_ctxt(key, len, ctx, ctxlen, &tr, &trlen))
158 {
159 case 0:
160 lua_pushlstring(L, tr, trlen);
161 return 1;
162
163 case -1:
164 return 0;
165 }
166
167 lua_pushnil(L);
168 lua_pushstring(L, "no catalog loaded");
169 return 2;
170 }
171
172 static int template_L_ntranslate(lua_State *L) {
173 size_t slen, plen, ctxlen = 0;
174 char *tr;
175 int trlen;
176 int n = luaL_checkinteger(L, 1);
177 const char *skey = luaL_checklstring(L, 2, &slen);
178 const char *pkey = luaL_checklstring(L, 3, &plen);
179 const char *ctx = luaL_optlstring(L, 4, NULL, &ctxlen);
180
181 switch (lmo_translate_plural_ctxt(n, skey, slen, pkey, plen, ctx, ctxlen, &tr, &trlen))
182 {
183 case 0:
184 lua_pushlstring(L, tr, trlen);
185 return 1;
186
187 case -1:
188 return 0;
189 }
190
191 lua_pushnil(L);
192 lua_pushstring(L, "no catalog loaded");
193 return 2;
194 }
195
196 static int template_L_hash(lua_State *L) {
197 size_t len;
198 const char *key = luaL_checklstring(L, 1, &len);
199 lua_pushinteger(L, sfh_hash(key, len));
200 return 1;
201 }
202
203
204 /* module table */
205 static const luaL_reg R[] = {
206 { "parse", template_L_parse },
207 { "parse_string", template_L_parse_string },
208 { "utf8", template_L_utf8 },
209 { "pcdata", template_L_pcdata },
210 { "striptags", template_L_striptags },
211 { "load_catalog", template_L_load_catalog },
212 { "close_catalog", template_L_close_catalog },
213 { "change_catalog", template_L_change_catalog },
214 { "get_translations", template_L_get_translations },
215 { "translate", template_L_translate },
216 { "ntranslate", template_L_ntranslate },
217 { "hash", template_L_hash },
218 { NULL, NULL }
219 };
220
221 LUALIB_API int luaopen_luci_template_parser(lua_State *L) {
222 luaL_register(L, TEMPLATE_LUALIB_META, R);
223 return 1;
224 }