1
// kdelibs4.js of Serbian KDE translation
3
// ------------------------------
4
// Property getter object contains the following data attributes:
5
// - callname: the name of the getter call as exposed to PO files
6
// - propkey: the key of the property as used in pmap files
7
// - overrides: dictionary of values of this property for certain phrases,
8
// which were manually set in the PO file
9
function Propgetter (callname, propkey)
11
this.callname = callname;
12
this.propkey = propkey;
15
this.getbase = Propgetter_getbase;
17
this.getprop = Propgetter_getprop;
18
this.getprop_uc = Propgetter_getprop_uc;
19
this.getform = Propgetter_getform;
20
this.getform_uc = Propgetter_getform_uc;
23
// Base of property/form getter methods attached to getter objects.
24
// First the property for the given phrase is looked up in overrides,
25
// and then in Transcript property map (read from pmap files).
26
// If the property is not found, fallback is signalled if retself is false,
27
// otherwise the phrase itself is returned.
28
function Propgetter_getbase (phrase, retself)
30
if (phrase in this.overrides) {
31
return this.overrides[phrase];
34
var prop = Ts.getProp(phrase, this.propkey)
35
if (prop != undefined)
44
// Property getter method attached to getter objects.
45
function Propgetter_getprop (phrase)
47
return this.getbase(phrase, false);
50
// As previous, but returns the property with the first letter upcased.
51
function Propgetter_getprop_uc (phrase)
53
var val = this.getprop(phrase);
55
// The second argument is indicating the number of alternatives per
56
// alternatives directive -- in case the first letter is within
57
// an alternatives directive, all alternatives in that directive
58
// should be processed.
59
return Ts.toUpperFirst(val, 2);
62
// Form getter method attached to getter objects.
63
function Propgetter_getform (phrase)
65
return this.getbase(phrase, true);
68
// As previous, but returns the form with the first letter upcased.
69
function Propgetter_getform_uc (phrase)
71
var val = this.getform(phrase);
72
// See the comment in Propgetter_getprop_uc().
73
return Ts.toUpperFirst(val, 2);
76
// ------------------------------
77
// Exposing property getters to PO.
79
// Contains all global property getters.
80
var _propgetters_ = {};
82
// Set PO calls for given property getter object.
83
function setcalls_prop (pgetr)
86
Ts.setcall(pgetr.callname, pgetr.getprop, pgetr);
87
// "Open with $[callname %1]"
90
Ts.setcall(pgetr.callname + "/ф", pgetr.getform, pgetr);
91
// "Open with $[callname/ф %1]"
93
// The calls which capitalize the first letter of the value,
94
// named as the default calls but with the first letter capitalized.
95
// Only set if the first letter of the call name is actually lowercase.
96
callname_uc = Ts.toUpperFirst(pgetr.callname);
97
if (callname_uc != pgetr.callname) {
98
Ts.setcall(callname_uc, pgetr.getprop_uc, pgetr);
99
// "$[Callname %1] starting..."
100
Ts.setcall(callname_uc + "/ф", pgetr.getform_uc, pgetr);
101
// "$[Callname/ф %1] starting..."
104
// Record getter objects globally.
105
// Only for the original name, since the uppercase/form variants are not
106
// used when properties are being set (when the global store is needed).
107
_propgetters_[pgetr.callname] = pgetr;
110
// Set property value of phrase.
111
function setprop (phrase, pkey, pval)
113
// Either create new, or select existing getter.
115
if (!_propgetters_[pkey]) {
116
// Populate new getter if not already defined.
117
pgetr = new Propgetter(pkey, pkey);
118
// Expose calls to PO.
119
setcalls_prop(pgetr);
122
// Get previously defined getter.
123
pgetr = _propgetters_[pkey];
126
// Add the property into overrides of selected getter.
127
pgetr.overrides[phrase] = pval;
130
// Get property value of phrase.
131
// Signals fallback if the property/phrase combination is not defined.
132
function getprop (phrase, pkey)
134
if (_propgetters_[pkey]) {
135
return _propgetters_[pkey].getprop(phrase);
140
// Get form of the phrase, or phrase itself if no such form.
141
function getform (phrase, fkey)
143
if (_propgetters_[fkey]) {
144
return _propgetters_[fkey].getform(phrase);
149
// Returns true if the phrase has the property.
150
function hasprop (phrase, pkey)
152
pg = _propgetters_[pkey];
156
if (!pg.overrides[phrase] && !Ts.getProp(phrase, pg.propkey)) {
162
// ------------------------------
163
// Predefined property getters.
165
// Call names and corresponding keys in pmap for predefined getters.
166
// The first letter in a call name should be lowercase; for each call
167
// another call with the first letter in uppercase will be defined,
168
// which will upcase the first letter in the property value before
170
var call_name_to_prop = {
172
"_изв" : "_izvor", // english original
173
"_род" : "_rod", // gender
174
"_број" : "_broj", // number
176
"ном" : "n", // nominative case
177
"ген" : "g", // genitive case
178
"дат" : "d", // dative case
179
"аку" : "a", // accusative case
180
"инс" : "i", // instrumental case
181
"лок" : "l", // locative case
183
// Expressive variants.
184
"наредбено" : "_narb", // command
185
"списковно" : "_spis", // listed
188
"ном-м" : "nm", // nominative, masculine
189
"ген-м" : "gm", // genitive, masculine
190
"дат-м" : "dm", // dative, masculine
191
"аку-м" : "am", // accusative, masculine
192
"инс-м" : "im", // instrumental, masculine
193
"лок-м" : "lm", // locative, masculine
194
"ном-ж" : "nz", // nominative, feminine
195
"ген-ж" : "gz", // genitive, feminine
196
"дат-ж" : "dz", // dative, feminine
197
"аку-ж" : "az", // accusative, feminine
198
"инс-ж" : "iz", // instrumental, feminine
199
"лок-ж" : "lz", // locative, feminine
200
"ном-с" : "ns", // nominative, neuter
201
"ген-с" : "gs", // genitive, neuter
202
"дат-с" : "ds", // dative, neuter
203
"аку-с" : "as", // accusative, neuter
204
"инс-с" : "is", // instrumental, neuter
205
"лок-с" : "ls", // locative, neuter
206
"ном-мк" : "nmk", // nominative, masculine, plural
207
"ген-мк" : "gmk", // genitive, masculine, plural
208
"дат-мк" : "dmk", // dative, masculine, plural
209
"аку-мк" : "amk", // accusative, masculine, plural
210
"инс-мк" : "imk", // instrumental, masculine, plural
211
"лок-мк" : "lmk", // locative, masculine, plural
212
"ном-жк" : "nzk", // nominative, feminine, plural
213
"ген-жк" : "gzk", // genitive, feminine, plural
214
"дат-жк" : "dzk", // dative, feminine, plural
215
"аку-жк" : "azk", // accusative, feminine, plural
216
"инс-жк" : "izk", // instrumental, feminine, plural
217
"лок-жк" : "lzk", // locative, feminine, plural
218
"ном-ск" : "nsk", // nominative, neuter, plural
219
"ген-ск" : "gsk", // genitive, neuter, plural
220
"дат-ск" : "dsk", // dative, neuter, plural
221
"аку-ск" : "ask", // accusative, neuter, plural
222
"инс-ск" : "isk", // instrumental, neuter, plural
223
"лок-ск" : "lsk", // locative, neuter, plural
226
// Create getter objects for predefined getters.
227
for (cname in call_name_to_prop) {
228
// Create getter object as defined above.
229
var pgetr = new Propgetter(cname, call_name_to_prop[cname]);
230
// Expose calls to PO.
231
setcalls_prop(pgetr);
234
// Special handling for instrumental case, when used for tool application:
235
// don't pass it along as-is if same as nominative case of the phrase,
236
// since the sentence can get very different, yet semantically correct meaning.
237
// Instead, pass genitive case with the preposition "by the help of".
239
var pgetr = new Propgetter("инс-п", "i");
241
// Replace default getter method.
242
pgetr.getprop = function (phrase)
244
var prop_ins = _propgetters_["инс"].getprop(phrase);
245
var prop_nom = _propgetters_["ном"].getprop(phrase);
246
if (prop_ins == prop_nom) {
247
var prop_gen = _propgetters_["ген"].getprop(phrase);
248
return "помоћу " + prop_gen;
255
setcalls_prop(pgetr);
258
// ------------------------------
259
// Set properties of the given phrase.
260
// The arguments to the call are the phrase, and a list of as many keys
261
// followed by their value as desired (i.e. number of elements must be even).
262
// Keys may also be comma-separated lists instead of a single key, in order
263
// not to have to repeat the same value when it corresponds to several keys.
265
// The property keys become property getters which can be used to retrive
266
// the value at a later point. If the getter for a given key already exists,
267
// the new value is added into its overrides.
269
// Returns undefined.
271
function setprops (phrase, keyvals)
273
if (keyvals.length % 2 != 0)
274
throw Error("Property setter given odd number of key/value elements.");
276
for (var i = 0; i < keyvals.length; i += 2) {
277
// Several keys may be given for a single prop, comma-separated.
278
var pkeys = keyvals[i].split(",");
279
var pval = keyvals[i + 1];
281
// Set the value to each property key.
282
for (var j = 0; j < pkeys.length; j += 1) {
283
setprop(phrase, pkeys[j], pval);
288
// Manually set properties of the phrase given by the finalized msgstr
289
// in the PO file and signal fallback.
290
// For the rest of the behavior, see setprops()
291
function setprops_msgstrf (/*...*/)
293
if (arguments.length % 2 != 0)
294
throw Error("Msgstr property setter given odd number of arguments.");
295
setprops(Ts.msgstrf(), arguments);
298
Ts.setcall("својства", setprops_msgstrf);
299
// "$[callname prop1 value1 prop2 value2 ...]"
301
// Manually set properties of the phrase given by the finalized msgstr
302
// in the PO file and return empty string.
303
// For the rest of the behavior, see setprops()
304
function setprops_msgstrf_e (/*...*/)
306
if (arguments.length % 2 != 0)
307
throw Error("Msgstr property setter given odd number of arguments.");
308
setprops(Ts.msgstrf(), arguments);
311
Ts.setcall("својства/п", setprops_msgstrf_e);
312
// "$[callname prop1 value1 prop2 value2 ...]"
314
// ------------------------------
315
// Manual plural handling.
316
// Only first three forms, as the fourth form is most likely not needed
317
// when the plural needs to be scripted.
318
// The first argument should be the proper value, not the substitution string
319
// (i.e. do not call as $[~ %1 ...] but as $[~ ^1 ...]).
320
function plural3 (n, form0, form1, form2)
322
if (n % 10 == 1 && n % 100 != 11)
324
else if (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20))
329
Ts.setcall("множ", plural3);
330
// "...and %2 $[callname ^2 file fila files]"
332
// ------------------------------
333
// Select one of three forms according to the gender of the phrase.
334
function select_by_gender (phrase, form_m, form_f, form_n)
336
// Select gender (throws fallback if phrase not found).
337
var gender = getprop(phrase, "_род");
342
else if (gender == "ж") {
345
else if (gender == "с") {
352
Ts.setcall("по-роду", select_by_gender);
353
// "Delete $[callname %1 this thisa thiso] %1?"
355
// ------------------------------
356
// Select one of two forms according to the number of the phrase.
357
function select_by_number (phrase, form_s, form_p)
359
// Select number (default to singular if not found).
361
if (hasprop(phrase, "_број")) {
362
number = getprop(phrase, "_број");
365
if (number == "к") { // plural
371
Ts.setcall("по-броју", select_by_number);
372
// "%1 $[callname %1 waalks waalk] by the river."
374
// ------------------------------
375
// Select one of six forms according to the gender and number of the phrase.
376
function select_by_number_gender (phrase,
377
form_ms, form_fs, form_ns, // singulars
378
form_mp, form_fp, form_np) // plurals
380
// Select number (default to singular if not found).
382
if (hasprop(phrase, "_број")) {
383
number = getprop(phrase, "_број");
386
if (number == "к") { // plural
387
return select_by_gender(phrase, form_mp, form_fp, form_np);
389
return select_by_gender(phrase, form_ms, form_fs, form_ns);
392
Ts.setcall("по-роду-броју", select_by_number_gender);
393
// "Delete $[callname %1 this thisa thiso thees theesa theeso] %1?"
395
// ------------------------------
396
// Select one the form according to the case and gender of another argument.
397
function select_by_case_gender (gcase, gphrase, phrase) // plurals
399
var gender = getprop(gphrase, "_род");
400
return getprop(phrase, gcase + "-" + gender);
402
Ts.setcall("по-падежу-роду", select_by_case_gender);
403
// "Delete $[callname case %2 %1] [case %2]?"
405
// ------------------------------
406
// Object to query whether a character is one of expected letters.
408
+ "абвгдђежзијклљмнњопрстћуфхцчџшАБВГДЂЕЖЗИЈКЛЉМНЊОПРСТЋУФХЦЧЏШ"
409
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
412
for (var i = 0; i < letter_arr.length; ++i) {
413
letter[letter_arr[i]] = 1;
416
// ------------------------------
417
// Split phrase into words and intersections,
418
// where words are taken as contiguous segments of letters.
419
// The return value is a tuple of arrays of words and intersections.
420
// There is always one more of intersections than words, so that
421
// the original phrase can be reassembled as
422
// intrs[0] + words[0] + ... + intrs[n - 2] + words[n - 2] + intrs[n - 1].
423
function split_phrase (phrase)
429
while (i < phrase.length) {
431
while (i1 < phrase.length && !letter[phrase[i1]]) {
434
intrs.push(phrase.substring(i, i1));
436
while (i2 < phrase.length && letter[phrase[i2]]) {
440
words.push(phrase.substring(i1, i2));
441
if (i2 == phrase.length) {
448
return [words, intrs];
451
// ------------------------------
452
// Apply call to each word in the phrase.
453
// The call must accept the word as the last argument.
454
function apply_to_word (/* phrase, callname, ...args before word... */)
456
if (arguments.length < 2)
457
throw Error("Applicator takes at least the phrase and the call name.");
459
phrase = arguments[0];
460
calln = arguments[1];
462
for (var i = 2; i < arguments.length; ++i) {
463
cargs.push(arguments[i]);
466
lst = split_phrase(phrase);
471
for (var i = 0; i < words.length; ++i) {
472
cargs.push(words[i]);
473
nwords.push(Ts.acall.apply(Ts, cargs));
478
for (var i = 0; i < nwords.length; ++i) {
479
str += intrs[i] + nwords[i];
481
str += intrs[nwords.length];
485
Ts.setcall("на-ријеч", apply_to_word);
486
// "Repeat until $[callname casecall %1], and on this date..."
488
// ------------------------------
489
// Decline person's name into given case.
490
// Parse name into first and last name, determine gender according to
491
// first name, decline according to gender and assemble.
492
// If name cannot be fully declined, returns original name if retself is true,
493
// otherwise signals fallback.
494
// TODO: Just delegates to ordinary getters for the time being.
495
function decline_person_name_base (gcase, fullname, retself)
498
return getform(fullname, gcase);
501
return getprop(fullname, gcase);
505
// Decline person's name, signal fallback if not possible.
506
function decline_person_name (gcase, fullname)
508
return decline_person_name_base(gcase, fullname, false);
510
Ts.setcall("именски", decline_person_name);
511
// "You have invited $[callname case %1] to the party."
513
// Decline person's name, return as-is if not possible.
514
function decline_person_name_nf (gcase, fullname)
516
return decline_person_name_base(gcase, fullname, true);
518
Ts.setcall("именски/ф", decline_person_name_nf);
519
// "You have invited $[callname case %1] to the party."
521
// ------------------------------
522
// Match style attributes to gender of the font family name,
523
// for the requested grammatical case.
524
// The message must have dynamic context 'family' equal to the family name,
525
// so that its gender can be obtained.
526
// Style string may be composed of several space-separated attributes.
527
// Family name and style attributes are expected in the nominative case.
528
// Returns composed style string in the proper gender/case.
529
function match_style_to_font (compstyle, gcase)
531
var family = Ts.dynctxt("family");
535
var gender = getprop(family, "_род");
537
if (hasprop(family, "_број")) {
538
number = getprop(family, "_број");
540
var styles = compstyle.split(" ");
542
for (var i = 0; i < styles.length; i += 1) {
543
final += " " + getprop(styles[i], gcase + "-" + gender + number);
545
return final.substr(1); // to remove initial space
547
Ts.setcall("стил-према-фонту", match_style_to_font);
549
// ------------------------------
550
// Pick a phrase depending on a dynamic context field.
551
// Input is the keyword of the context field, followed by pairs of
552
// regex matcher on context value and corresponding phrase,
553
// and optionally followed by default phrase in case the value does not match.
554
// If the value does not match and default phrase is not given,
555
// fallback is signaled.
556
// If requested dynamic context field does not exist, fallback is signaled.
557
function select_by_context (/* ctxt_key,
558
valrx_1, phrase_1, ..., valrx_N, phrase_N
559
[, default_phrase]*/)
561
if (arguments.length < 1)
562
throw Error("Selector by context takes at least the context keyword.");
564
var ctxtkey = arguments[0];
565
var ctxtval = Ts.dynctxt(ctxtkey);
568
for (var i = 1; i < arguments.length; i += 2) {
569
if (ctxtval.match(RegExp(arguments[i]))) {
570
phrase = arguments[i + 1];
574
if (phrase == undefined) {
575
if (arguments.length % 2 == 0) {
576
phrase = arguments[arguments.length - 1];
584
Ts.setcall("по-контексту", select_by_context);
586
// ------------------------------
587
// Load property maps.
588
Ts.loadProps("trapnakron");
589
// // Do not load fonts pmap if the user requested so.
590
// if (!Ts.getConfBool("translate-fonts", true)) {