[asterisk-commits] tilghman: trunk r168832 - in /trunk: ./ apps/ include/asterisk/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Jan 16 12:49:09 CST 2009


Author: tilghman
Date: Fri Jan 16 12:49:09 2009
New Revision: 168832

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=168832
Log:
Merged revisions 168828 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
  r168828 | tilghman | 2009-01-16 12:41:35 -0600 (Fri, 16 Jan 2009) | 6 lines
  
  Fix the conjugation of Russian and Ukrainian languages.
  (related to issue #12475)
   Reported by: chappell
   Patches: 
         vm_multilang.patch uploaded by chappell (license 8)
........

Modified:
    trunk/   (props changed)
    trunk/apps/app_voicemail.c
    trunk/include/asterisk/say.h
    trunk/main/say.c

Propchange: trunk/
------------------------------------------------------------------------------
Binary property 'branch-1.4-merged' - no diff available.

Modified: trunk/apps/app_voicemail.c
URL: http://svn.digium.com/svn-view/asterisk/trunk/apps/app_voicemail.c?view=diff&rev=168832&r1=168831&r2=168832
==============================================================================
--- trunk/apps/app_voicemail.c (original)
+++ trunk/apps/app_voicemail.c Fri Jan 16 12:49:09 2009
@@ -7174,7 +7174,102 @@
 	return res;
 }
 
-/* Hebrew syntax */
+/* Version of vm_intro() designed to work for many languages.
+ *
+ * It is hoped that this function can prevent the proliferation of 
+ * language-specific vm_intro() functions and in time replace the language-
+ * specific functions which already exist.  An examination of the language-
+ * specific functions revealed that they all corrected the same deficiencies
+ * in vm_intro_en() (which was the default function). Namely:
+ *
+ *  1) The vm-Old and vm-INBOX sound files were overloaded.  The English 
+ *     wording of the voicemail greeting hides this problem.  For example,
+ *     vm-INBOX contains only the word "new".  This means that both of these
+ *     sequences produce valid utterances:
+ *      * vm-youhave digit/1 vm-INBOX vm-message (you have one new message)
+ *      * vm-press digit/1 vm-for vm-INBOX vm-messages (press 1 for new messages)
+ *     However, if we rerecord vm-INBOX to say "the new" (which is unavoidable
+ *     in many languages) the first utterance becomes "you have 1 the new message".
+ *  2) The function contains hardcoded rules for pluralizing the word "message".
+ *     These rules are correct for English, but not for many other languages.
+ *  3) No attempt is made to pluralize the adjectives ("old" and "new") as
+ *     required in many languages.
+ *  4) The gender of the word for "message" is not specified. This is a problem
+ *     because in many languages the gender of the number in phrases such
+ *     as "you have one new message" must match the gender of the word
+ *     meaning "message".
+ *
+ * Fixing these problems for each new language has meant duplication of effort.
+ * This new function solves the problems in the following general ways:
+ *  1) Add new sound files vm-new and vm-old.  These can be linked to vm-INBOX
+ *     and vm-Old respectively for those languages where it makes sense.
+ *  2) Call ast_say_counted_noun() to put the proper gender and number prefix
+ *     on vm-message.
+ *  3) Call ast_say_counted_adjective() to put the proper gender and number
+ *     prefix on vm-new and vm-old (none for English).
+ *  4) Pass the gender of the language's word for "message" as an agument to
+ *     this function which is can in turn pass on to the functions which 
+ *     say numbers and put endings on nounds and adjectives.
+ *
+ * All languages require these messages:
+ *  vm-youhave		"You have..."
+ *  vm-and		"and"
+ *  vm-no		"no" (in the sense of "none", as in "you have no messages")
+ *
+ * To use it for English, you will need these additional sound files:
+ *  vm-new		"new"
+ *  vm-message		"message", singular
+ *  vm-messages		"messages", plural
+ *
+ * If you use it for Russian and other slavic languages, you will need these additional sound files:
+ *
+ *  vm-newn		"novoye" (singular, neuter)
+ *  vm-newx		"novikh" (counting plural form, genative plural)
+ *  vm-message		"sobsheniye" (singular form)
+ *  vm-messagex1	"sobsheniya" (first counting plural form, genative singular)
+ *  vm-messagex2	"sobsheniy" (second counting plural form, genative plural)
+ *  digits/1n		"odno" (neuter singular for phrases such as "one message" or "thirty one messages")
+ *  digits/2n		"dva" (neuter singular)
+ */
+static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
+{
+	int res;
+	int lastnum = 0;
+
+	res = ast_play_and_wait(chan, "vm-youhave");
+
+	if (!res && vms->newmessages) {
+		lastnum = vms->newmessages;
+
+		if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
+			res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
+		}
+
+		if (!res && vms->oldmessages) {
+			res = ast_play_and_wait(chan, "vm-and");
+		}
+	}
+
+	if (!res && vms->oldmessages) {
+		lastnum = vms->oldmessages;
+
+		if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
+			res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
+		}
+	}
+
+	if (!res) {
+		if (lastnum == 0) {
+			res = ast_play_and_wait(chan, "vm-no");
+		} else {
+			res = ast_say_counted_noun(chan, lastnum, "vm-message");
+		}
+	}
+
+	return res;
+}
+
+/* Default Hebrew syntax */
 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
 {
 	int res = 0;
@@ -7857,78 +7952,6 @@
 	return res;
 }
 
-static int get_lastdigits(int num)
-{
-	num %= 100;
-	return (num < 20) ? num : num % 10;
-}
-
-static int vm_intro_ru(struct ast_channel *chan,struct vm_state *vms)
-{
-	int res;
-	int lastnum = 0;
-	int dcnum;
-
-	res = ast_play_and_wait(chan, "vm-youhave");
-	if (!res && vms->newmessages) {
-		lastnum = get_lastdigits(vms->newmessages);
-		dcnum = vms->newmessages - lastnum;
-		if (dcnum)
-			res = say_and_wait(chan, dcnum, chan->language);
-		if (!res && lastnum) {
-			if (lastnum == 1) 
-				res = ast_play_and_wait(chan, "digits/odno");
-			else
-				res = say_and_wait(chan, lastnum, chan->language);
-		}
-
-		if (!res)
-			res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-novoe" : "vm-novyh");
-
-		if (!res && vms->oldmessages)
-			res = ast_play_and_wait(chan, "vm-and");
-	}
-
-	if (!res && vms->oldmessages) {
-		lastnum = get_lastdigits(vms->oldmessages);
-		dcnum = vms->oldmessages - lastnum;
-		if (dcnum)
-			res = say_and_wait(chan, dcnum, chan->language);
-		if (!res && lastnum) {
-			if (lastnum == 1) 
-				res = ast_play_and_wait(chan, "digits/odno");
-			else
-				res = say_and_wait(chan, lastnum, chan->language);
-		}
-
-		if (!res)
-			res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-staroe" : "vm-staryh");
-	}
-
-	if (!res && !vms->newmessages && !vms->oldmessages) {
-		lastnum = 0;
-		res = ast_play_and_wait(chan, "vm-no");
-	}
-
-	if (!res) {
-		switch (lastnum) {
-		case 1:
-			res = ast_play_and_wait(chan, "vm-soobshenie");
-			break;
-		case 2:
-		case 3:
-		case 4:
-			res = ast_play_and_wait(chan, "vm-soobsheniya");
-			break;
-		default:
-			res = ast_play_and_wait(chan, "vm-soobsheniy");
-			break;
-		}
-	}
-
-	return res;
-}
-
 /* CHINESE (Taiwan) syntax */
 static int vm_intro_tw(struct ast_channel *chan, struct vm_state *vms)
 {
@@ -7965,77 +7988,6 @@
 		if (!res)
 			res = ast_play_and_wait(chan, "vm-messages");
 	}
-	return res;
-}
-
-/* UKRAINIAN syntax */
-/* in ukrainian the syntax is different so we need the following files
- * --------------------------------------------------------
- * /digits/ua/1e 'odne'
- * vm-nove       'nove'
- * vm-stare      'stare'
- */
-static int vm_intro_ua(struct ast_channel *chan,struct vm_state *vms)
-{
-	int res;
-	int lastnum = 0;
-	int dcnum;
-
-	res = ast_play_and_wait(chan, "vm-youhave");
-	if (!res && vms->newmessages) {
-		lastnum = get_lastdigits(vms->newmessages);
-		dcnum = vms->newmessages - lastnum;
-		if (dcnum)
-			res = say_and_wait(chan, dcnum, chan->language);
-		if (!res && lastnum) {
-			if (lastnum == 1) 
-				res = ast_play_and_wait(chan, "digits/ua/1e");
-			else
-				res = say_and_wait(chan, lastnum, chan->language);
-		}
-
-		if (!res)
-			res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-nove" : "vm-INBOX");
-
-		if (!res && vms->oldmessages)
-			res = ast_play_and_wait(chan, "vm-and");
-	}
-
-	if (!res && vms->oldmessages) {
-		lastnum = get_lastdigits(vms->oldmessages);
-		dcnum = vms->oldmessages - lastnum;
-		if (dcnum)
-			res = say_and_wait(chan, dcnum, chan->language);
-		if (!res && lastnum) {
-			if (lastnum == 1) 
-				res = ast_play_and_wait(chan, "digits/ua/1e");
-			else
-				res = say_and_wait(chan, lastnum, chan->language);
-		}
-
-		if (!res)
-			res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-stare" : "vm-Old");
-	}
-
-	if (!res && !vms->newmessages && !vms->oldmessages) {
-		lastnum = 0;
-		res = ast_play_and_wait(chan, "vm-no");
-	}
-
-	if (!res) {
-		switch (lastnum) {
-		case 1:
-		case 2:
-		case 3:
-		case 4:
-			res = ast_play_and_wait(chan, "vm-message");
-			break;
-		default:
-			res = ast_play_and_wait(chan, "vm-messages");
-			break;
-		}
-	}
-
 	return res;
 }
 
@@ -8079,11 +8031,11 @@
 	} else if (!strcasecmp(chan->language, "no")) {	/* NORWEGIAN syntax */
 		return vm_intro_no(chan, vms);
 	} else if (!strcasecmp(chan->language, "ru")) { /* RUSSIAN syntax */
-		return vm_intro_ru(chan, vms);
+		return vm_intro_multilang(chan, vms, "n");
 	} else if (!strcasecmp(chan->language, "tw")) { /* CHINESE (Taiwan) syntax */
 		return vm_intro_tw(chan, vms);
 	} else if (!strcasecmp(chan->language, "ua")) { /* UKRAINIAN syntax */
-		return vm_intro_ua(chan, vms);
+		return vm_intro_multilang(chan, vms, "n");
 	} else if (!strcasecmp(chan->language, "he")) { /* HEBREW syntax */
 		 return vm_intro_he(chan, vms);
 	} else {					/* Default to ENGLISH */

Modified: trunk/include/asterisk/say.h
URL: http://svn.digium.com/svn-view/asterisk/trunk/include/asterisk/say.h?view=diff&rev=168832&r1=168831&r2=168832
==============================================================================
--- trunk/include/asterisk/say.h (original)
+++ trunk/include/asterisk/say.h Fri Jan 16 12:49:09 2009
@@ -163,6 +163,10 @@
 
 SAY_EXTERN int (* ast_say_date_with_format)(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *timezone) SAY_INIT(ast_say_date_with_format);
 
+int ast_say_counted_noun(struct ast_channel *chan, int num, const char *noun);
+
+int ast_say_counted_adjective(struct ast_channel *chan, int num, const char *adjective, const char *gender);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif

Modified: trunk/main/say.c
URL: http://svn.digium.com/svn-view/asterisk/trunk/main/say.c?view=diff&rev=168832&r1=168831&r2=168832
==============================================================================
--- trunk/main/say.c (original)
+++ trunk/main/say.c Fri Jan 16 12:49:09 2009
@@ -50,6 +50,7 @@
 #include "asterisk/lock.h"
 #include "asterisk/localtime.h"
 #include "asterisk/utils.h"
+#include "asterisk/app.h"
 
 /* Forward declaration */
 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang);
@@ -7754,6 +7755,114 @@
 	return res;
 }
 
+/* In English, we use the plural for everything but one. For example:
+ *  1 degree
+ *  2 degrees
+ *  5 degrees
+ * The filename for the plural form is generated by appending "s". Note that
+ * purpose is to generate a unique filename, not to implement irregular 
+ * declensions. Thus:
+ *  1 man
+ *  2 mans (the "mans" soundfile will of course say "men")
+ */
+static const char *counted_noun_ending_en(int num)
+{
+	if (num == 1 || num == -1) {
+		return "";
+	} else {
+		return "s";
+	}
+}
+
+/* Counting of objects in slavic languages such as Russian and Ukrainian the
+ * rules are more complicated. There are two plural forms used in counting.
+ * They are the genative singular which we represent with the suffix "x1" and 
+ * the genative plural which we represent with the suffix "x2". The base names
+ * of the soundfiles remain in English. For example:
+ *  1 degree (soudfile says "gradus")
+ *  2 degreex1 (soundfile says "gradusa")
+ *  5 degreex2 (soundfile says "gradusov")
+ */
+static const char *counted_noun_ending_slavic(int num)
+{
+    	if (num < 0) {
+	    num *= -1;
+	}
+	num %= 100;			/* never pay attention to more than two digits */
+	if (num >= 20) {		/* for numbers 20 and above, pay attention to only last digit */
+	    num %= 10;
+	}
+	if (num == 1) {			/* singular */
+	    return "";
+	}
+	if (num > 0 && num < 5) {	/* 2--5 get genative singular */
+	    return "x1";
+	} else {			/* 5--19 get genative plural */
+	    return "x2";
+	}
+}
+
+int ast_say_counted_noun(struct ast_channel *chan, int num, const char noun[])
+{
+	char *temp;
+	int temp_len;
+	const char *ending;
+	if (!strcasecmp(chan->language, "ru")) {		/* Russian */
+		ending = counted_noun_ending_slavic(num);
+	} else if(!strcasecmp(chan->language, "ua")) {		/* Ukrainian */
+		ending = counted_noun_ending_slavic(num);
+	} else if(!strcasecmp(chan->language, "ua")) {		/* Polish */
+		ending = counted_noun_ending_slavic(num);
+	} else {						/* English and default */
+		ending = counted_noun_ending_en(num);
+	}
+	temp = alloca((temp_len = (strlen(noun) + strlen(ending) + 1)));
+	snprintf(temp, temp_len, "%s%s", noun, ending);
+	return ast_play_and_wait(chan, temp);
+}
+
+/*
+ * In slavic languages such as Russian and Ukrainian the rules for declining
+ * adjectives are simpler than those for nouns.  When counting we use only
+ * the singular (to which we give no suffix) and the genative plural (which
+ * we represent by adding an "x").  Oh, an in the singular gender matters
+ * so we append the supplied gender suffix ("m", "f", "n").
+ */
+static const char *counted_adjective_ending_ru(int num, const char gender[])
+{
+    	if (num < 0) {
+	    num *= -1;
+	}
+	num %= 100;		/* never pay attention to more than two digits */
+	if (num >= 20) {	/* at 20 and beyond only the last digit matters */
+	    num %= 10;
+	}
+	if (num == 1) {
+	    return gender ? gender : "";
+	} else {		/* all other numbers get the genative plural */
+	    return "x";
+	}
+}
+
+int ast_say_counted_adjective(struct ast_channel *chan, int num, const char adjective[], const char gender[])
+{
+	char *temp;
+	int temp_len;
+	const char *ending;
+	if (!strcasecmp(chan->language, "ru")) {			/* Russian */
+		ending = counted_adjective_ending_ru(num, gender);
+	} else if (!strcasecmp(chan->language, "ua")) {			/* Ukrainian */
+		ending = counted_adjective_ending_ru(num, gender);
+	} else if (!strcasecmp(chan->language, "pl")) {			/* Polish */
+		ending = counted_adjective_ending_ru(num, gender);
+	} else {							/* English and default */
+		ending = "";
+	}
+	temp = alloca((temp_len = (strlen(adjective) + strlen(ending) + 1)));
+	snprintf(temp, temp_len, "%s%s", adjective, ending);
+	return ast_play_and_wait(chan, temp);
+}
+
 
 
 /*




More information about the asterisk-commits mailing list