i18nema 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|