1 | var fs = require('fs'),
|
2 | path = require('path');
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | module.exports = function i18n(compound, root) {
|
8 | var app = compound.app;
|
9 | root = root || compound.root;
|
10 | var dir = root + '/config/locales';
|
11 |
|
12 | if (!app) {
|
13 | return;
|
14 | }
|
15 |
|
16 | if (!compound.utils.existsSync(dir)) {
|
17 | app.set('i18n', 'off');
|
18 | }
|
19 |
|
20 | if (app.set('locale') === 'off' || app.set('i18n') === 'off') {
|
21 | compound.T = function () {
|
22 | return function (path, defVal) {
|
23 | return defVal;
|
24 | };
|
25 | };
|
26 | compound.t = compound.T();
|
27 | return;
|
28 | } else {
|
29 | compound.t = T(true);
|
30 | compound.T = T;
|
31 | }
|
32 |
|
33 | load(dir, compound);
|
34 |
|
35 | |
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 | function T(global) {
|
42 | if (global) {
|
43 |
|
44 |
|
45 | return function t(path, locale, defaultValue) {
|
46 | if (!locale) {
|
47 | throw new Error('Locale expected');
|
48 | }
|
49 | return translate(path, locale, defaultValue);
|
50 | };
|
51 | } else {
|
52 |
|
53 |
|
54 | return function t(path, defaultValue) {
|
55 | return translate(path, t.locale, defaultValue);
|
56 | };
|
57 | }
|
58 |
|
59 | function translate(path, locale, defaultValue) {
|
60 | var translation = compound.__localeData[locale], substitute;
|
61 |
|
62 | function nextPathItem(token) {
|
63 | return (translation = translation[token]);
|
64 | }
|
65 |
|
66 | if (typeof path === 'string') {
|
67 | substitute = false;
|
68 | } else {
|
69 | substitute = path;
|
70 | path = substitute.shift();
|
71 | }
|
72 |
|
73 | if (!translation || !path.split('.').every(nextPathItem)) {
|
74 | translation = typeof defaultValue === 'undefined' ?
|
75 | translationMissing(locale, path, defaultValue) :
|
76 | defaultValue;
|
77 | }
|
78 |
|
79 | if (translation && substitute && substitute.length) {
|
80 | substitute.forEach(function(substitution) {
|
81 | translation = translation.replace(/%/, substitution.toString().replace(/%/g, ''));
|
82 | });
|
83 | }
|
84 |
|
85 | return translation;
|
86 | }
|
87 |
|
88 | function translationMissing(locale, path, defaultValue) {
|
89 |
|
90 | if (compound.parent) {
|
91 | var translation;
|
92 | translation = compound.parent.t(path, locale, defaultValue);
|
93 | if (translation) {
|
94 | return translation;
|
95 | }
|
96 |
|
97 | }
|
98 |
|
99 | switch (app.settings.translationMissing) {
|
100 | case 'display':
|
101 | return 'translation missing for ' + locale + '.' + path;
|
102 | case 'default':
|
103 | case undefined:
|
104 | var defLocale = app.settings.defaultLocale;
|
105 | return !defLocale || locale === defLocale ? '' : translate(path, defLocale, defaultValue);
|
106 | }
|
107 | }
|
108 | }
|
109 |
|
110 | T.localeSupported = function(localeName) {
|
111 | return !!compound.__localeData[localeName];
|
112 | };
|
113 | };
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 | function load(dir, compound) {
|
127 | var coffee;
|
128 | fs.readdirSync(dir).forEach(function(file) {
|
129 | if (file.match(/^\./)) return;
|
130 |
|
131 | var filename = dir + '/' + file;
|
132 | var code = fs.readFileSync(filename, 'utf8').toString();
|
133 | var obj;
|
134 |
|
135 | try {
|
136 | if (file.match(/\.ya?ml$/)) {
|
137 | var yaml = require(['yaml', 'js'].join('-')),
|
138 | obj = yaml.load(code);
|
139 | if (obj.shift) {
|
140 | obj = obj.shift();
|
141 | }
|
142 | } else if (file.match(/\.json/)) {
|
143 | obj = JSON.parse(code);
|
144 | } else if (file.match(/\.coffee/)) {
|
145 | coffee = coffee || require('coffee-script');
|
146 | obj = coffee.eval(code);
|
147 | } else {
|
148 | console.log('Unsupported extension of locale file ' + filename);
|
149 | }
|
150 | } catch (e) {
|
151 | console.log('Parsing file ' + filename);
|
152 | console.log(e);
|
153 | console.log(e.stack);
|
154 | }
|
155 |
|
156 | if (obj) {
|
157 | addTranslation(obj, compound);
|
158 | }
|
159 |
|
160 | });
|
161 | }
|
162 |
|
163 |
|
164 |
|
165 |
|
166 | function addTranslation(lang, compound) {
|
167 | Object.keys(lang).forEach(function(localeName) {
|
168 | var translations = lang[localeName];
|
169 | if (compound.locales.indexOf(localeName) === -1) {
|
170 | compound.locales.push([localeName, translations.lang && translations.lang.name || localeName]);
|
171 | }
|
172 | compound.__localeData[localeName] = compound.__localeData[localeName] || {};
|
173 | Object.keys(translations).forEach(function(namespace) {
|
174 | if ('object' === typeof compound.__localeData[localeName] && namespace in compound.__localeData[localeName]) {
|
175 | merge(compound.__localeData[localeName][namespace], translations[namespace]);
|
176 | } else {
|
177 | compound.__localeData[localeName][namespace] = translations[namespace];
|
178 | }
|
179 | });
|
180 | });
|
181 |
|
182 | function merge(dest, data) {
|
183 | for (var i in data) {
|
184 | if (i in dest && typeof dest[i] === 'object') {
|
185 | merge(dest[i], data[i]);
|
186 | } else {
|
187 | dest[i] = data[i];
|
188 | }
|
189 | }
|
190 | }
|
191 | }
|