i18nema 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +25 -0
- data/Rakefile +19 -0
- data/ext/i18nema/extconf.h +3 -0
- data/ext/i18nema/extconf.rb +5 -0
- data/ext/i18nema/gram.h +79 -0
- data/ext/i18nema/i18nema.c +397 -0
- data/ext/i18nema/mkrf_conf.rb +19 -0
- data/ext/i18nema/syck.h +453 -0
- data/ext/i18nema/uthash.h +940 -0
- data/ext/i18nema/yamlbyte.h +171 -0
- data/lib/i18nema/core_ext/hash.rb +8 -0
- data/lib/i18nema.rb +42 -0
- data/test/helper.rb +5 -0
- data/test/i18nema_test.rb +78 -0
- metadata +94 -0
data/README.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# I18nema
|
2
|
+
|
3
|
+
Fast I18n backend to keep things running smoothly.
|
4
|
+
|
5
|
+
I18nema is a drop-in replacement for I18n::Backend::Simple, for faster
|
6
|
+
lookups and quicker gc runs. Translations are stored outside of the ruby
|
7
|
+
heap, and lookups happen in C (rather than the usual inject on nested
|
8
|
+
ruby hashes).
|
9
|
+
|
10
|
+
## How do I use it?
|
11
|
+
|
12
|
+
gem 'i18nema'
|
13
|
+
|
14
|
+
and then do something like this in an initializer:
|
15
|
+
|
16
|
+
I18n.backend = I18nema::Backend.new
|
17
|
+
|
18
|
+
As with I18n::Backend::Simple, you can pull in additional features, e.g.
|
19
|
+
|
20
|
+
I18nema::Backend.send(:include, I18n::Backend::Fallbacks)
|
21
|
+
|
22
|
+
## Notes
|
23
|
+
|
24
|
+
You should probably make sure translations are loaded before you fork. In
|
25
|
+
an initializer, just do `I18n.backend.init_translations`
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/extensiontask'
|
3
|
+
|
4
|
+
desc 'Default: run unit tests.'
|
5
|
+
task :default => :test
|
6
|
+
|
7
|
+
require 'rake/testtask'
|
8
|
+
desc 'Test the immigrant plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.libs << 'test'
|
12
|
+
t.pattern = 'test/**/*_test.rb'
|
13
|
+
t.verbose = true
|
14
|
+
end
|
15
|
+
Rake::Task[:test].prerequisites << :compile
|
16
|
+
|
17
|
+
Rake::ExtensionTask.new('i18nema') do |ext|
|
18
|
+
ext.lib_dir = File.join('lib', 'i18nema')
|
19
|
+
end
|
data/ext/i18nema/gram.h
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
/* A Bison parser, made by GNU Bison 1.875d. */
|
2
|
+
|
3
|
+
/* Skeleton parser for Yacc-like parsing with Bison,
|
4
|
+
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
|
5
|
+
|
6
|
+
This program is free software; you can redistribute it and/or modify
|
7
|
+
it under the terms of the GNU General Public License as published by
|
8
|
+
the Free Software Foundation; either version 2, or (at your option)
|
9
|
+
any later version.
|
10
|
+
|
11
|
+
This program is distributed in the hope that it will be useful,
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
GNU General Public License for more details.
|
15
|
+
|
16
|
+
You should have received a copy of the GNU General Public License
|
17
|
+
along with this program; if not, write to the Free Software
|
18
|
+
Foundation, Inc., 59 Temple Place - Suite 330,
|
19
|
+
Boston, MA 02111-1307, USA. */
|
20
|
+
|
21
|
+
/* As a special exception, when this file is copied by Bison into a
|
22
|
+
Bison output file, you may use that output file without restriction.
|
23
|
+
This special exception was added by the Free Software Foundation
|
24
|
+
in version 1.24 of Bison. */
|
25
|
+
|
26
|
+
/* Tokens. */
|
27
|
+
#ifndef YYTOKENTYPE
|
28
|
+
# define YYTOKENTYPE
|
29
|
+
/* Put the tokens into the symbol table, so that GDB and other debuggers
|
30
|
+
know about them. */
|
31
|
+
enum yytokentype {
|
32
|
+
YAML_ANCHOR = 258,
|
33
|
+
YAML_ALIAS = 259,
|
34
|
+
YAML_TRANSFER = 260,
|
35
|
+
YAML_TAGURI = 261,
|
36
|
+
YAML_ITRANSFER = 262,
|
37
|
+
YAML_WORD = 263,
|
38
|
+
YAML_PLAIN = 264,
|
39
|
+
YAML_BLOCK = 265,
|
40
|
+
YAML_DOCSEP = 266,
|
41
|
+
YAML_IOPEN = 267,
|
42
|
+
YAML_INDENT = 268,
|
43
|
+
YAML_IEND = 269
|
44
|
+
};
|
45
|
+
#endif
|
46
|
+
#define YAML_ANCHOR 258
|
47
|
+
#define YAML_ALIAS 259
|
48
|
+
#define YAML_TRANSFER 260
|
49
|
+
#define YAML_TAGURI 261
|
50
|
+
#define YAML_ITRANSFER 262
|
51
|
+
#define YAML_WORD 263
|
52
|
+
#define YAML_PLAIN 264
|
53
|
+
#define YAML_BLOCK 265
|
54
|
+
#define YAML_DOCSEP 266
|
55
|
+
#define YAML_IOPEN 267
|
56
|
+
#define YAML_INDENT 268
|
57
|
+
#define YAML_IEND 269
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
|
63
|
+
#line 35 "gram.y"
|
64
|
+
typedef union YYSTYPE {
|
65
|
+
SYMID nodeId;
|
66
|
+
SyckNode *nodeData;
|
67
|
+
char *name;
|
68
|
+
} YYSTYPE;
|
69
|
+
/* Line 1285 of yacc.c. */
|
70
|
+
#line 71 "gram.h"
|
71
|
+
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
72
|
+
# define YYSTYPE_IS_DECLARED 1
|
73
|
+
# define YYSTYPE_IS_TRIVIAL 1
|
74
|
+
#endif
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
|
@@ -0,0 +1,397 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <syck.h>
|
3
|
+
#include "uthash.h"
|
4
|
+
|
5
|
+
VALUE I18nema = Qnil,
|
6
|
+
I18nemaBackend = Qnil,
|
7
|
+
I18nemaBackendLoadError = Qnil;
|
8
|
+
|
9
|
+
struct i_object;
|
10
|
+
struct i_key_value;
|
11
|
+
static VALUE array_to_rarray(struct i_object *array);
|
12
|
+
static VALUE hash_to_rhash(struct i_object *hash);
|
13
|
+
static void merge_hash(struct i_object *hash, struct i_object *other_hash);
|
14
|
+
static void delete_hash(struct i_key_value **hash);
|
15
|
+
static void delete_object(struct i_object *object);
|
16
|
+
|
17
|
+
enum i_object_type {
|
18
|
+
i_type_string,
|
19
|
+
i_type_array,
|
20
|
+
i_type_hash
|
21
|
+
};
|
22
|
+
|
23
|
+
union i_object_data {
|
24
|
+
char *string;
|
25
|
+
struct i_object **array;
|
26
|
+
struct i_key_value *hash;
|
27
|
+
};
|
28
|
+
|
29
|
+
typedef struct i_object
|
30
|
+
{
|
31
|
+
unsigned long size;
|
32
|
+
enum i_object_type type;
|
33
|
+
union i_object_data data;
|
34
|
+
} i_object_t;
|
35
|
+
|
36
|
+
typedef struct i_key_value
|
37
|
+
{
|
38
|
+
char *key;
|
39
|
+
struct i_object *value;
|
40
|
+
UT_hash_handle hh;
|
41
|
+
} i_key_value_t;
|
42
|
+
|
43
|
+
static int current_translation_count = 0;
|
44
|
+
static ID s_to_s,
|
45
|
+
s_init_translations;
|
46
|
+
|
47
|
+
static VALUE
|
48
|
+
i_object_to_robject(i_object_t *object) {
|
49
|
+
if (object == NULL)
|
50
|
+
return Qnil;
|
51
|
+
switch (object->type) {
|
52
|
+
case i_type_string:
|
53
|
+
return rb_str_new2(object->data.string);
|
54
|
+
case i_type_array:
|
55
|
+
return array_to_rarray(object);
|
56
|
+
case i_type_hash:
|
57
|
+
return hash_to_rhash(object);
|
58
|
+
}
|
59
|
+
return Qnil;
|
60
|
+
}
|
61
|
+
|
62
|
+
static VALUE
|
63
|
+
array_to_rarray(i_object_t *array)
|
64
|
+
{
|
65
|
+
VALUE result = rb_ary_new2(array->size);
|
66
|
+
for (unsigned long i = 0; i < array->size; i++)
|
67
|
+
rb_ary_store(result, i, i_object_to_robject(array->data.array[i]));
|
68
|
+
return result;
|
69
|
+
}
|
70
|
+
|
71
|
+
static VALUE
|
72
|
+
hash_to_rhash(i_object_t *hash)
|
73
|
+
{
|
74
|
+
i_key_value_t *handle = hash->data.hash;
|
75
|
+
VALUE result = rb_hash_new();
|
76
|
+
for (; handle != NULL; handle = handle->hh.next)
|
77
|
+
rb_hash_aset(result, rb_str_new2(handle->key), i_object_to_robject(handle->value));
|
78
|
+
return result;
|
79
|
+
}
|
80
|
+
|
81
|
+
static i_object_t*
|
82
|
+
root_object_get(VALUE self)
|
83
|
+
{
|
84
|
+
i_object_t *root_object;
|
85
|
+
VALUE translations;
|
86
|
+
translations = rb_iv_get(self, "@translations");
|
87
|
+
Data_Get_Struct(translations, i_object_t, root_object);
|
88
|
+
return root_object;
|
89
|
+
}
|
90
|
+
|
91
|
+
/*
|
92
|
+
* call-seq:
|
93
|
+
* backend.direct_lookup([part]+) -> localized_str
|
94
|
+
*
|
95
|
+
* Returns the translation(s) found under the specified key.
|
96
|
+
*
|
97
|
+
* backend.direct_lookup("en", "foo", "bar") #=> "lol"
|
98
|
+
* backend.direct_lookup("en", "foo") #=> {"bar"=>"lol", "baz"=>["asdf", "qwerty"]}
|
99
|
+
*/
|
100
|
+
|
101
|
+
static VALUE
|
102
|
+
direct_lookup(int argc, VALUE *argv, VALUE self)
|
103
|
+
{
|
104
|
+
i_object_t *result = root_object_get(self);;
|
105
|
+
i_key_value_t *kv = NULL;
|
106
|
+
VALUE rs;
|
107
|
+
char *s;
|
108
|
+
|
109
|
+
for (int i = 0; i < argc && result != NULL && result->type == i_type_hash; i++) {
|
110
|
+
rs = rb_funcall(argv[i], s_to_s, 0);
|
111
|
+
s = StringValueCStr(rs);
|
112
|
+
HASH_FIND_STR(result->data.hash, s, kv);
|
113
|
+
result = kv == NULL ? NULL : kv->value;
|
114
|
+
}
|
115
|
+
|
116
|
+
return i_object_to_robject(result);
|
117
|
+
}
|
118
|
+
|
119
|
+
static void
|
120
|
+
empty_object(i_object_t *object)
|
121
|
+
{
|
122
|
+
if (object == NULL)
|
123
|
+
return;
|
124
|
+
|
125
|
+
switch (object->type) {
|
126
|
+
case i_type_string:
|
127
|
+
xfree(object->data.string);
|
128
|
+
break;
|
129
|
+
case i_type_array:
|
130
|
+
for (unsigned long i = 0; i < object->size; i++)
|
131
|
+
delete_object(object->data.array[i]);
|
132
|
+
xfree(object->data.array);
|
133
|
+
break;
|
134
|
+
case i_type_hash:
|
135
|
+
delete_hash(&object->data.hash);
|
136
|
+
break;
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
static void
|
141
|
+
delete_object(i_object_t *object)
|
142
|
+
{
|
143
|
+
empty_object(object);
|
144
|
+
xfree(object);
|
145
|
+
}
|
146
|
+
|
147
|
+
static void
|
148
|
+
delete_key_value(i_key_value_t *kv, int delete_value)
|
149
|
+
{
|
150
|
+
if (delete_value)
|
151
|
+
delete_object(kv->value);
|
152
|
+
xfree(kv->key);
|
153
|
+
xfree(kv);
|
154
|
+
}
|
155
|
+
|
156
|
+
static void
|
157
|
+
delete_hash(i_key_value_t **hash)
|
158
|
+
{
|
159
|
+
i_key_value_t *kv, *tmp;
|
160
|
+
HASH_ITER(hh, *hash, kv, tmp) {
|
161
|
+
HASH_DEL(*hash, kv);
|
162
|
+
delete_key_value(kv, 1);
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
static void
|
167
|
+
add_key_value(i_key_value_t **hash, i_key_value_t *kv)
|
168
|
+
{
|
169
|
+
i_key_value_t *existing = NULL;
|
170
|
+
HASH_FIND_STR(*hash, kv->key, existing);
|
171
|
+
|
172
|
+
if (existing != NULL) {
|
173
|
+
if (existing->value->type == i_type_hash && kv->value->type == i_type_hash) {
|
174
|
+
merge_hash(existing->value, kv->value);
|
175
|
+
delete_key_value(kv, 0);
|
176
|
+
return;
|
177
|
+
}
|
178
|
+
HASH_DEL(*hash, existing);
|
179
|
+
delete_key_value(existing, 1);
|
180
|
+
}
|
181
|
+
HASH_ADD_KEYPTR(hh, *hash, kv->key, strlen(kv->key), kv);
|
182
|
+
}
|
183
|
+
|
184
|
+
static void
|
185
|
+
merge_hash(i_object_t *hash, i_object_t *other_hash)
|
186
|
+
{
|
187
|
+
i_key_value_t *kv, *tmp;
|
188
|
+
|
189
|
+
HASH_ITER(hh, other_hash->data.hash, kv, tmp) {
|
190
|
+
HASH_DEL(other_hash->data.hash, kv);
|
191
|
+
add_key_value(&hash->data.hash, kv);
|
192
|
+
}
|
193
|
+
delete_object(other_hash);
|
194
|
+
}
|
195
|
+
|
196
|
+
static int
|
197
|
+
delete_syck_st_entry(char *key, char *value, char *arg)
|
198
|
+
{
|
199
|
+
return ST_DELETE;
|
200
|
+
}
|
201
|
+
|
202
|
+
static int
|
203
|
+
delete_syck_object(char *key, char *value, char *arg)
|
204
|
+
{
|
205
|
+
i_object_t *object = (i_object_t *)value;
|
206
|
+
delete_object(object);
|
207
|
+
return ST_DELETE;
|
208
|
+
}
|
209
|
+
|
210
|
+
static void
|
211
|
+
handle_syck_error(SyckParser *parser, const char *str)
|
212
|
+
{
|
213
|
+
char *endl = parser->cursor;
|
214
|
+
while (*endl != '\0' && *endl != '\n')
|
215
|
+
endl++;
|
216
|
+
endl[0] = '\0';
|
217
|
+
|
218
|
+
if (parser->syms)
|
219
|
+
st_foreach(parser->syms, delete_syck_object, 0);
|
220
|
+
rb_raise(I18nemaBackendLoadError, "%s on line %d, col %ld: `%s'", str, parser->linect + 1, parser->cursor - parser->lineptr, parser->lineptr);
|
221
|
+
}
|
222
|
+
|
223
|
+
static SyckNode*
|
224
|
+
handle_syck_badanchor(SyckParser *parser, char *anchor)
|
225
|
+
{
|
226
|
+
char error[strlen(anchor) + 14];
|
227
|
+
sprintf(error, "bad anchor `%s'", anchor);
|
228
|
+
handle_syck_error(parser, error);
|
229
|
+
return NULL;
|
230
|
+
}
|
231
|
+
|
232
|
+
static SYMID
|
233
|
+
handle_syck_node(SyckParser *parser, SyckNode *node)
|
234
|
+
{
|
235
|
+
i_object_t *result;
|
236
|
+
result = ALLOC(i_object_t);
|
237
|
+
SYMID oid;
|
238
|
+
|
239
|
+
switch (node->kind) {
|
240
|
+
case syck_str_kind:
|
241
|
+
// TODO: why does syck sometimes give us empty string nodes? (small) memory leak, since they never end up in a seq/map
|
242
|
+
result->type = i_type_string;
|
243
|
+
result->size = node->data.str->len;
|
244
|
+
result->data.string = xmalloc(node->data.str->len + 1);
|
245
|
+
strncpy(result->data.string, node->data.str->ptr, node->data.str->len);
|
246
|
+
result->data.string[node->data.str->len] = '\0';
|
247
|
+
break;
|
248
|
+
case syck_seq_kind:
|
249
|
+
result->type = i_type_array;
|
250
|
+
result->size = node->data.list->idx;
|
251
|
+
result->data.array = ALLOC_N(i_object_t*, node->data.list->idx);
|
252
|
+
for (long i = 0; i < node->data.list->idx; i++) {
|
253
|
+
i_object_t *item = NULL;
|
254
|
+
|
255
|
+
oid = syck_seq_read(node, i);
|
256
|
+
syck_lookup_sym(parser, oid, (void **)&item);
|
257
|
+
if (item->type == i_type_string)
|
258
|
+
current_translation_count++;
|
259
|
+
result->data.array[i] = item;
|
260
|
+
}
|
261
|
+
break;
|
262
|
+
case syck_map_kind:
|
263
|
+
result->type = i_type_hash;
|
264
|
+
result->data.hash = NULL;
|
265
|
+
for (long i = 0; i < node->data.pairs->idx; i++) {
|
266
|
+
i_object_t *key = NULL, *value = NULL;
|
267
|
+
|
268
|
+
oid = syck_map_read(node, map_key, i);
|
269
|
+
syck_lookup_sym(parser, oid, (void **)&key);
|
270
|
+
oid = syck_map_read(node, map_value, i);
|
271
|
+
syck_lookup_sym(parser, oid, (void **)&value);
|
272
|
+
|
273
|
+
i_key_value_t *kv;
|
274
|
+
kv = ALLOC(i_key_value_t);
|
275
|
+
kv->key = key->data.string;
|
276
|
+
xfree(key);
|
277
|
+
kv->value = value;
|
278
|
+
if (value->type == i_type_string)
|
279
|
+
current_translation_count++;
|
280
|
+
add_key_value(&result->data.hash, kv);
|
281
|
+
}
|
282
|
+
break;
|
283
|
+
}
|
284
|
+
|
285
|
+
|
286
|
+
return syck_add_sym(parser, (char *)result);
|
287
|
+
}
|
288
|
+
|
289
|
+
/*
|
290
|
+
* call-seq:
|
291
|
+
* backend.load_yaml_string(yaml_str) -> num_translations
|
292
|
+
*
|
293
|
+
* Loads translations from the specified yaml string, and returns the
|
294
|
+
* number of (new) translations stored.
|
295
|
+
*
|
296
|
+
* backend.load_yaml_string("en:\n foo: bar") #=> 1
|
297
|
+
*/
|
298
|
+
|
299
|
+
static VALUE
|
300
|
+
load_yml_string(VALUE self, VALUE yml)
|
301
|
+
{
|
302
|
+
SYMID oid;
|
303
|
+
i_object_t *root_object = root_object_get(self);
|
304
|
+
i_object_t *new_root_object = NULL;
|
305
|
+
current_translation_count = 0;
|
306
|
+
SyckParser* parser = syck_new_parser();
|
307
|
+
syck_parser_handler(parser, handle_syck_node);
|
308
|
+
StringValue(yml);
|
309
|
+
syck_parser_str(parser, RSTRING_PTR(yml), RSTRING_LEN(yml), NULL);
|
310
|
+
syck_parser_bad_anchor_handler(parser, handle_syck_badanchor);
|
311
|
+
syck_parser_error_handler(parser, handle_syck_error);
|
312
|
+
|
313
|
+
oid = syck_parse(parser);
|
314
|
+
syck_lookup_sym(parser, oid, (void **)&new_root_object);
|
315
|
+
if (parser->syms)
|
316
|
+
st_foreach(parser->syms, delete_syck_st_entry, 0);
|
317
|
+
syck_free_parser(parser);
|
318
|
+
if (new_root_object == NULL || new_root_object->type != i_type_hash) {
|
319
|
+
delete_object(new_root_object);
|
320
|
+
rb_raise(I18nemaBackendLoadError, "root yml node is not a hash");
|
321
|
+
}
|
322
|
+
merge_hash(root_object, new_root_object);
|
323
|
+
|
324
|
+
return INT2NUM(current_translation_count);
|
325
|
+
}
|
326
|
+
|
327
|
+
/*
|
328
|
+
* call-seq:
|
329
|
+
* backend.available_locales -> locales
|
330
|
+
*
|
331
|
+
* Returns the currently loaded locales. Order is not guaranteed.
|
332
|
+
*
|
333
|
+
* backend.available_locales #=> [:en, :es]
|
334
|
+
*/
|
335
|
+
|
336
|
+
static VALUE
|
337
|
+
available_locales(VALUE self)
|
338
|
+
{
|
339
|
+
if (!RTEST(rb_iv_get(self, "@initialized")))
|
340
|
+
rb_funcall(self, s_init_translations, 0);
|
341
|
+
i_object_t *root_object = root_object_get(self);
|
342
|
+
i_key_value_t *current = root_object->data.hash;
|
343
|
+
VALUE ary = rb_ary_new2(0);
|
344
|
+
|
345
|
+
for (; current != NULL; current = current->hh.next)
|
346
|
+
rb_ary_push(ary, rb_str_intern(rb_str_new2(current->key)));
|
347
|
+
|
348
|
+
return ary;
|
349
|
+
}
|
350
|
+
|
351
|
+
/*
|
352
|
+
* call-seq:
|
353
|
+
* backend.reload! -> true
|
354
|
+
*
|
355
|
+
* Clears out all currently stored translations.
|
356
|
+
*
|
357
|
+
* backend.reload! #=> true
|
358
|
+
*/
|
359
|
+
|
360
|
+
static VALUE
|
361
|
+
reload(VALUE self)
|
362
|
+
{
|
363
|
+
i_object_t *root_object = root_object_get(self);
|
364
|
+
empty_object(root_object);
|
365
|
+
rb_iv_set(self, "@initialized", Qfalse);
|
366
|
+
root_object = NULL;
|
367
|
+
return Qtrue;
|
368
|
+
}
|
369
|
+
|
370
|
+
static VALUE
|
371
|
+
initialize(VALUE self)
|
372
|
+
{
|
373
|
+
VALUE translations;
|
374
|
+
i_object_t *root_object = ALLOC(i_object_t);
|
375
|
+
root_object->type = i_type_hash;
|
376
|
+
root_object->data.hash = NULL;
|
377
|
+
translations = Data_Wrap_Struct(I18nemaBackend, 0, delete_object, root_object);
|
378
|
+
rb_iv_set(self, "@translations", translations);
|
379
|
+
return self;
|
380
|
+
}
|
381
|
+
|
382
|
+
void
|
383
|
+
Init_i18nema()
|
384
|
+
{
|
385
|
+
I18nema = rb_define_module("I18nema");
|
386
|
+
I18nemaBackend = rb_define_class_under(I18nema, "Backend", rb_cObject);
|
387
|
+
I18nemaBackendLoadError = rb_define_class_under(I18nemaBackend, "LoadError", rb_eStandardError);
|
388
|
+
|
389
|
+
s_to_s = rb_intern("to_s");
|
390
|
+
s_init_translations = rb_intern("init_translations");
|
391
|
+
|
392
|
+
rb_define_method(I18nemaBackend, "initialize", initialize, 0);
|
393
|
+
rb_define_method(I18nemaBackend, "load_yml_string", load_yml_string, 1);
|
394
|
+
rb_define_method(I18nemaBackend, "available_locales", available_locales, 0);
|
395
|
+
rb_define_method(I18nemaBackend, "reload!", reload, 0);
|
396
|
+
rb_define_method(I18nemaBackend, "direct_lookup", direct_lookup, -1);
|
397
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubygems/command.rb'
|
3
|
+
require 'rubygems/dependency_installer.rb'
|
4
|
+
begin
|
5
|
+
Gem::Command.build_args = ARGV
|
6
|
+
rescue NoMethodError
|
7
|
+
end
|
8
|
+
inst = Gem::DependencyInstaller.new
|
9
|
+
begin
|
10
|
+
if RUBY_VERSION >= "2.0"
|
11
|
+
inst.install "syck", "1.0.0"
|
12
|
+
end
|
13
|
+
rescue
|
14
|
+
exit(1)
|
15
|
+
end
|
16
|
+
|
17
|
+
f = File.open(File.join(File.dirname(__FILE__), "Rakefile"), "w") # create dummy rakefile to indicate success
|
18
|
+
f.write("task :default\n")
|
19
|
+
f.close
|