Makefile.in | 7 ++ modes/Makefile.in | 2 +- xlock/Makefile.in | 7 +- xlock/XLock-ja.ad | 2 + xlock/XLock-ru.ad | 21 ++++ xlock/XLock.ad | 2 + xlock/msgmerge.c | 83 ++++++++++++++++ xlock/msgmerge.h | 20 ++++ xlock/resource-msg-en.h | 4 +- xlock/resource.c | 13 +++ xlock/xlock.c | 252 +++++++++++++++++++++++------------------------ 11 files changed, 277 insertions(+), 136 deletions(-) diff --git a/Makefile.in b/Makefile.in index 7d99255..00e7ee1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -9,7 +9,7 @@ MAKEIN_SUBDIR = for dir in $(SUBDIRS) ; do ( cd $$dir ; sed s/@MODULES@/\#/ Makefile.in > Makefile ; $(MAKE) $@ ) ; done all : - @+$(MAKE_SUBDIR) + for dir in $(SUBDIRS); do $(MAKE) -C $$dir all; done # this tells GNU make not to export variables into the environment # But other makes do not understand its significance, so it must @@ -32,7 +32,14 @@ RM = rm -f VER = xlockmore +datadir = @datadir@ + install : + cd po; \ + for po in */*/*.po; do \ + msgfmt "$$po" -o "$${po%.po}.mo" && \ + install -p -m640 -D "$${po%.po}.mo" "$(datadir)/locale"/"$${po%.po}.mo"; \ + done @+$(MAKE_SUBDIR) install-program : diff --git a/modes/Makefile.in b/modes/Makefile.in index 053d36c..aefdcea 100644 --- a/modes/Makefile.in +++ b/modes/Makefile.in @@ -54,7 +54,7 @@ XLOCKUTILOBJS = $(DOU)xlock$(OU)passwd$(OU)resource$(OU)parsecmd$(O)$(S)\ $(DOU)util$(OU)logout$(OU)mode$(OU)xlockimage$(OU)ras$(OU)xbm$(O)$(S)\ $(DOU)vis$(OU)visgl$(OU)color$(OU)random$(OU)iostuff$(OU)automata$(O)$(S)\ $(DOU)spline$(OU)sound$(OU)erase$(OU)magick$(O)$(S)\ -$(DOU)vtlock$(OU)vtlock_proc$(O) +$(DOU)vtlock$(OU)vtlock_proc$(OU)msgmerge$(O) # This debugging is new and is untested on many systems. @CHECK@CHECKDEF = -DDEBUG diff --git a/xlock/Makefile.in b/xlock/Makefile.in index 7577bf0..06bf5a3 100644 --- a/xlock/Makefile.in +++ b/xlock/Makefile.in @@ -6,6 +6,7 @@ # @SET_MAKE@ datarootdir = @datarootdir@ +pkgdatadir = @datadir@/@PACKAGE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ @@ -44,17 +45,17 @@ XLOCKUTILOBJS = $(DOU)xlock$(OU)passwd$(OU)resource$(OU)parsecmd$(O)$(S)\ $(DOU)util$(OU)logout$(OU)mode$(OU)xlockimage$(OU)ras$(OU)xbm$(O)$(S)\ $(DOU)vis$(OU)visgl$(OU)color$(OU)random$(OU)iostuff$(OU)automata$(O)$(S)\ $(DOU)spline$(OU)sound$(OU)erase$(OU)magick$(O)$(S)\ -$(DOU)vtlock$(OU)vtlock_proc$(O)$(S)$(XLOCKCHECKOBJS) +$(DOU)vtlock$(OU)vtlock_proc$(OU)msgmerge$(O)$(S)$(XLOCKCHECKOBJS) XLOCKCHECKSRCS = $(DU)memcheck$(C) XLOCKUTILHDRS = xlock.h mode.h vroot.h xlockimage.h ras.h \ -version.h config.h +version.h config.h msgmerge.h XLOCKUTILSRCS = $(DU)xlock$(CU)passwd$(CU)resource$(CU)parsecmd$(C) \ $(DU)util$(CU)logout$(CU)mode$(CU)xlockimage$(CU)ras$(CU)xbm$(C) \ $(DU)vis$(CU)visgl$(CU)color$(CU)random$(CU)iostuff$(CU)automata$(C) \ $(DU)spline$(CU)sound$(CU)erase$(CU)magick$(C) \ -$(DU)vtlock$(CU)vtlock_proc$(C) $(XLOCKCHECKSRCS) +$(DU)vtlock$(CU)vtlock_proc$(CU)msgmerge$(C) $(XLOCKCHECKSRCS) # default target all : $(XLOCKUTILOBJS) diff --git a/xlock/XLock-ja.ad b/xlock/XLock-ja.ad index ce9efd5..d49564c 100644 --- a/xlock/XLock-ja.ad +++ b/xlock/XLock-ja.ad @@ -1,4 +1,6 @@ !! Japanese by: YOKOTA Hiroshi +XLock.fontset: -*-droid sans mono-bold-*-normal--24-*-,-*-*-bold-*-normal--14-*-,-*-*-medium-*-normal--14-*- +XLock.planfontset: -*-droid sans mono-bold-*-normal--12-*-,-*-*-bold-*-normal--12-*- XLock.username: ログイン名: XLock.password: パスワード: XLock.info: Enter パスワードを入力して下さい。アイコンをクリックすると再ロックします。 diff --git a/xlock/XLock-ru.ad b/xlock/XLock-ru.ad new file mode 100644 index 0000000..95548c8 --- /dev/null +++ b/xlock/XLock-ru.ad @@ -0,0 +1,21 @@ +!! Russian by Paul Wolneykien +XLock.fontset: -*-droid sans mono-bold-*-normal--24-*-,-*-*-bold-*-normal--14-*-,-*-*-medium-*-normal--14-*- +XLock.planfontset: -*-droid sans mono-bold-*-normal--12-*-,-*-*-bold-*-normal--12-*- +XLock.username: 仄: +XLock.password: 舒仂仍: +XLock.info: 于亠亟亳亠 仗舒仂仍, 仂弍 仆 弍仍仂从亳仂于从. 舒亢仄亳亠 亳从仂仆从 亟仍 仗仂仄仂舒 亰舒舒于从亳. +XLock.validate: 亠仆亳亳从舒亳... +XLock.invalid: 亳弍从舒 舒亠仆亳亳从舒亳亳. +XLock.invalidCapsLock: 亳弍从舒 舒亠仆亳亳从舒亳亳, 仆亳仄舒仆亳亠! CapsLock 于从仍ム亠仆. +XLock.logoutButtonLabel: 舒于亠亳 亠舒仆 +XLock.logoutButtonHelp: \ + 仄仂亢亠亠 亰舒于亠亳 亟舒仆仆亶 亠舒仆 亳 仆舒舒 仆仂于亶, 亠仍亳 磲仂仄\n\ +仆亠 于仂弍仂亟仆 舒弍仂亳 仄亠.\n\ +: 舒于亠亠仆亳亠 亠舒仆舒 仗亳于亠亟 从 舒于舒亳亶仆仂仄 亰舒于亠亠仆亳\n\ +于亠 亰舒仗亠仆仆 仗仂仍亰仂于舒亠仍亠仄 仗仂亞舒仄仄, 仗仂仂仄 亳仗仂仍亰亶亠\n\ +亟舒仆仆 于仂亰仄仂亢仆仂 仂仍从仂 于 仂仄 仍舒亠, 亠仍亳 仗仂仍亰仂于舒亠仍,\n\ +亰舒仗亳于亳亶 亠舒仆, 仆亠亟仂仗亠仆. +XLock.logoutFailedString: \ +仂仗从舒 亰舒于亠亠仆亳 亠舒仆舒 丕弌亂.\n\ +弌亠舒仆 亟舒仆仆仂亞仂 仗仂仍亰仂于舒亠仍 仆亠 仄仂亢亠 弍 舒于仂仄舒亳亠从亳 亰舒于亠仆. +XLock.logoutAuto: 仂仗从舒 舒于仂仄舒亳亠从仂亞仂 亰舒于亠亠仆亳 亠舒仆舒 仆亠 亟舒仍舒. diff --git a/xlock/XLock.ad b/xlock/XLock.ad index 0dc2b6b..5e0025d 100644 --- a/xlock/XLock.ad +++ b/xlock/XLock.ad @@ -107,6 +107,8 @@ before logging them out. XLock.logoutFailedString: \ Logout attempt FAILED.\n\ Current user could not be automatically logged out. +XLock.attempt: %d failed attempt. +XLock.attempts: %d failed attempts. ! Mode options: If count, cycles, or size options are set to 1 ... ! they are probably not used by the mode. diff --git a/xlock/msgmerge.c b/xlock/msgmerge.c new file mode 100644 index 0000000..92f9485 --- /dev/null +++ b/xlock/msgmerge.c @@ -0,0 +1,83 @@ +#include +#include +#include "msgmerge.h" + +/* A function to merge one piece of text with another. + * Current text contained in the 'buf' argument should + * include one or more fragments inside square brackets. + * New text in the 'msg' argument should contain '*' + * characters in number equal to the number of fragments + * outside the square brackets in the current text. + * When merged, the '*' characters in the new text are + * replaced by the correcponding fragments of current text + * outside the brackets. Text inside brackets isn't used + * and so is missed. + * Resulted text is saved in the buffer 'buf'. To avoid + * possible overflow the 'buflen' argument is used to + * specify a maximum size of data in the buffer 'buf'. + */ +char *msgmerge(char *buf, const char *msg, int buflen) +{ + int i, ib, jb; + char *tmp; + + /* Allocate a buffer for merge. */ + tmp = malloc(buflen); + if (tmp == NULL) + { + return NULL; + } + + /* Put initial copy of the 'msg'. */ + strncpy(tmp, msg, buflen); + tmp[buflen - 1] = '\0'; + + i = 0; + ib = jb = 0; + while (i < strlen(tmp) && ib < strlen(buf)) + { + /* Search for the next asterisk. */ + for (; i < strlen(tmp) && (tmp[i] != '*' || \ + ((i > 0) && tmp[i-1] == '\\')); i++); + if (i < strlen(tmp)) { + /* Replacement position found. Search for next + * fragment outside the brackets. */ + if (buf[ib] == '[') { + for (; ib < strlen(buf) && (buf[ib] != ']' || \ + ((ib > 0) && buf[ib-1] == '\\')); ib++); + if ((ib + 1) < strlen(buf)) { + ib++; + } + } + for (jb = ib; jb < strlen(buf) && (buf[jb] != '[' || \ + ((jb > 0) && buf[jb-1] == '\\')); jb++); + if (ib < strlen(buf)) { + /* Shift remaining part of 'msg' by jb - ib. */ + if ((i + jb - ib) < buflen) { + memmove(tmp + i + jb - ib, tmp + i + 1, \ + (strlen(tmp) + jb - ib) < buflen ? \ + strlen(tmp) - i : buflen - i - jb + ib); + } + /* Replace asterisk by the fragment. */ + strncpy(tmp + i, buf + ib, (i + jb - ib) < buflen ? \ + jb - ib : buflen - i); + i += jb - ib; + ib = ib; + } + } + } + + strncpy(buf, tmp, buflen); + free(tmp); + + return buf; +} + +/* Copying 'msgmerge' version with separate source and destination + * buffers. */ +char *cmsgmerge +(char *mbuf, const char *buf, const char *msg, int mbuflen) +{ + strncpy(mbuf, buf, mbuflen); + return msgmerge(mbuf, msg, mbuflen); +} diff --git a/xlock/msgmerge.h b/xlock/msgmerge.h new file mode 100644 index 0000000..aab26cc --- /dev/null +++ b/xlock/msgmerge.h @@ -0,0 +1,20 @@ +/* A function to merge one piece of text with another. + * Current text contained in the 'buf' argument should + * include one or more fragments inside square brackets. + * New text in the 'msg' argument should contain '*' + * characters in number equal to the number of fragments + * outside the square brackets in the current text. + * When merged, the '*' characters in the new text are + * replaced by the correcponding fragments of current text + * outside the brackets and the text inside brackets is + * removed along with the brackets. + * Resulted text is saved in the buffer 'buf'. To avoid + * possible overflow the 'buflen' argument is used to + * specify a maximum text length in the buffer 'buf'. + */ +char *msgmerge(char *buf, const char *msg, int buflen); + +/* Copying 'msgmerge' version with separate source and destination + * buffers. */ +char *cmsgmerge +(char *mbuf, const char *buf, const char *msg, int mbuflen); diff --git a/xlock/resource-msg-en.h b/xlock/resource-msg-en.h index 61a5782..fd15703 100644 --- a/xlock/resource-msg-en.h +++ b/xlock/resource-msg-en.h @@ -16,8 +16,8 @@ #define DEF_KRBINFO "Enter Kerberos password to unlock; select icon to lock." #endif /* HAVE_KRB5 */ -#define DEF_COUNT_FAILED " failed attempt." -#define DEF_COUNTS_FAILED " failed attempts." +#define DEF_COUNT_FAILED "%d failed attempt." +#define DEF_COUNTS_FAILED "%d failed attempts." /* string that appears in logout button */ #define DEF_BTN_LABEL "Logout" diff --git a/xlock/resource.c b/xlock/resource.c index 1f72d73..b24bbc9 100644 --- a/xlock/resource.c +++ b/xlock/resource.c @@ -72,6 +72,7 @@ static const char sccsid[] = "@(#)resource.c 4.08 98/08/04 xlockmore"; #include "vis.h" #include "iostuff.h" #include "version.h" +#include #if VMS # if ( __VMS_VER < 70000000 ) # ifdef __DECC @@ -1731,12 +1732,23 @@ getAppResources(char *homeenv, char **custom, XrmDatabase * RDB, XrmDatabase cmdlineDB = (XrmDatabase) NULL; XrmDatabase userDB = (XrmDatabase) NULL; XrmDatabase applicationDB = (XrmDatabase) NULL; + char *lang; + char *lclassname; + XrmDatabase localeDB = (XrmDatabase) NULL; env = getenv("XFILESEARCHPATH"); applicationDB = parsefilepath( ((env == NULL) ? (char *) DEF_FILESEARCHPATH : env), "app-defaults", classname, *custom); + lang = setlocale(LC_ALL, NULL); + lclassname = (char *) malloc(strlen(classname) + strlen(lang) + 2); + strcat(strcat(strcpy(lclassname, classname), "."), lang); + localeDB = parsefilepath( + ((env == NULL) ? (char *) DEF_FILESEARCHPATH : env), + "app-defaults", lclassname, *custom); + free(lclassname); + XrmParseCommand(&cmdlineDB, cmdlineTable, cmdlineEntries, ProgramName, argc, argv); @@ -1770,6 +1782,7 @@ getAppResources(char *homeenv, char **custom, XrmDatabase * RDB, free(userfile); (void) XrmMergeDatabases(applicationDB, RDB); + (void) XrmMergeDatabases(localeDB, RDB); (void) XrmMergeDatabases(userDB, RDB); /* PURIFY 4.0.1 on Solaris 2 reports an uninitialized memory read on the next * line. PURIFY 4.0.1 on SunOS4 does not report this error. */ diff --git a/xlock/xlock.c b/xlock/xlock.c index 9fa2970..b215b5a 100644 --- a/xlock/xlock.c +++ b/xlock/xlock.c @@ -582,6 +582,9 @@ xlockmore_screenhack(Display * dpy, Window window, } #else /* STANDALONE */ +#include +#include +#include "msgmerge.h" #include "xlock.h" #include "color.h" #include "util.h" @@ -1572,7 +1575,7 @@ static void statusUpdate(int isnew, int scr) { int left, x, y, len; - char buf[1024]; + char buf[1024], mbuf[1024]; XWindowAttributes xgwa; static int last_time; @@ -1657,28 +1657,59 @@ y = timey; if (timeelapsed) { - if (len < 60) { - if (len == 1) - (void) sprintf(buf, TIME_ELAPSED_MINUTE, len); - else - (void) sprintf(buf, TIME_ELAPSED_MINUTES, len); - } else { - (void) sprintf(buf, TIME_ELAPSED_HOURS, len / 60, len % 60); - } - putText(dsp, Scr[scr].window, Scr[scr].textgc, buf, False, left, &x, &y); - } + if (len < 60) + (void) sprintf(buf, + ngettext("%d minute elapsed since locked.", + "%d minutes elapsed since locked.", + len), + len); + else { + (void) sprintf(buf, + ngettext("%d hour[ elapsed since locked.]", + "%d hours[ elapsed since locked.]", + len / 60), + len / 60); + (void) sprintf(buf, + cmsgmerge(mbuf, buf, + ngettext("* %02d minute[ elapsed since locked.]", + "* %02d minutes[ elapsed since locked.]", + len % 60), + sizeof(buf)), + len % 60); + (void) sprintf(buf, + cmsgmerge(mbuf, buf, gettext("* elapsed since locked."), + sizeof(buf))); + } + putText(dsp, Scr[scr].window, Scr[scr].textgc, buf, False, left, &x, &y); + } #ifdef USE_BUTTON_LOGOUT if (enable_button) { if (logoutButton > len) { int tmp = logoutButton - len; if (tmp < 60) { - if (tmp == 1) - (void) sprintf(buf, BUTTON_MINUTE, tmp); - else - (void) sprintf(buf, BUTTON_MINUTES, tmp); - } else { - (void) sprintf(buf, BUTTON_HOURS, tmp / 60, tmp % 60); + (void) sprintf(buf, + ngettext("%d minute until the public logout button appears.", + "%d minutes until the public logout button appears.", + tmp), + tmp); + } else { + (void) sprintf(buf, + ngettext("%d hour[ until public logout button appears.]", + "%d hours[ until public logout button appears.]", + tmp / 60), + tmp / 60); + (void) sprintf(buf, + cmsgmerge(mbuf, buf, + ngettext("* %02d minute[ until public logout button appears.]", + "* %02d minutes[ until public logout button appears.]", + tmp % 60), + sizeof(buf)), + tmp % 60); + (void) sprintf(buf, + cmsgmerge(mbuf, buf, + gettext("* until public logout button appears."), + sizeof(buf))); } putText(dsp, Scr[scr].window, Scr[scr].textgc, buf, False, left, &x, &y); } else { @@ -1725,12 +1756,28 @@ int tmp = logoutAuto - len; if (tmp < 60) { - if (tmp == 1) - (void) sprintf(buf, AUTOLOGOUT_MINUTE, tmp); - else - (void) sprintf(buf, AUTOLOGOUT_MINUTES, tmp); - } else { - (void) sprintf(buf, AUTOLOGOUT_HOURS, tmp / 60, tmp % 60); + (void) sprintf(buf, + ngettext("%d minute until auto-logout.", + "%d minutes until auto-logout.", + tmp), + tmp); + } else { + (void) sprintf(buf, + ngettext("%d hour[ until auto-logout.]", + "%d hours[ until auto-logout.]", + tmp / 60), + tmp / 60); + (void) sprintf(buf, + cmsgmerge(mbuf, buf, + ngettext("* %02d minute[ until auto-logout.]", + "* %02d minutes[ until auto-logout.]", + tmp % 60), + sizeof(buf)), + tmp % 60); + (void) sprintf(buf, + cmsgmerge(mbuf, buf, + gettext("* until auto-logout."), + sizeof(buf))); } putText(dsp, Scr[scr].window, Scr[scr].textgc, buf, False, left, &x, &y); } @@ -2489,21 +2489,22 @@ putText(dsp, Scr[screen].window, Scr[screen].textgc, text_info, False, left, &x, &y); putText(dsp, Scr[screen].window, Scr[screen].textgc, "\n", False, left, &x, &y); if (count_failed > 0) { - char * cnt = NULL; + char *cntt, *cnt = NULL; + int cntlen = 0; y += fontHeight + 6; if (y < Scr[screen].iconpos.y + iconheight + fontAscent + 14) y = Scr[screen].iconpos.y + iconheight + fontAscent + 14; x = left = Scr[screen].iconpos.x; - if ((cnt = (char *) malloc(strlen((count_failed == 1) ? failed_attempt : failed_attempts) + 16)) != NULL) { - (void) sprintf(cnt, "%d%s", count_failed, - (count_failed == 1) ? failed_attempt : failed_attempts); - putText(dsp, Scr[screen].window, Scr[screen].textgc, - cnt, False, left, &x, &y); - putText(dsp, Scr[screen].window, Scr[screen].textgc, - "\n", False, left, &x, &y); - free(cnt); - y -= 2 * (fontHeight + 6); /* go up */ - } + cntt = ngettext(failed_attempt, failed_attempts, count_failed); + cntlen = strlen(cntt) + 16; + cnt = (char *) malloc(cntlen); + snprintf(cnt, cntlen, cntt, count_failed); + putText(dsp, Scr[screen].window, Scr[screen].textgc, + cnt, False, left, &x, &y); + free(cnt); + putText(dsp, Scr[screen].window, Scr[screen].textgc, + "\n", False, left, &x, &y); + y -= 2 * (fontHeight + 6); /* go up */ } timex = x; timey = y; @@ -2793,20 +2794,21 @@ XTextWidth(font, textInvalid, strlen(textInvalid)), fontHeight + 5 + screenOffset); if (count_failed > 0) { - char * cnt = NULL; + char *cntt, *cnt = NULL; + int cntlen = 0; y += fontHeight + 6; if (y < Scr[screen].iconpos.y + iconheight + fontAscent + 14) y = Scr[screen].iconpos.y + iconheight + fontAscent + 14; x = left = Scr[screen].iconpos.x; - if ((cnt = (char *) malloc(strlen((count_failed == 1) ? failed_attempt : failed_attempts) + 16)) != NULL) { - (void) sprintf(cnt, "%d%s", count_failed, - (count_failed == 1) ? failed_attempt : failed_attempts); - putText(dsp, Scr[screen].window, Scr[screen].textgc, - cnt, False, left, &x, &y); - putText(dsp, Scr[screen].window, Scr[screen].textgc, - "\n", False, left, &x, &y); - free(cnt); - } + cntt = ngettext(failed_attempt, failed_attempts, count_failed); + cntlen = strlen(cntt) + 16; + cnt = (char *) malloc(cntlen); + snprintf(cnt, cntlen, cntt, count_failed); + putText(dsp, Scr[screen].window, Scr[screen].textgc, + cnt, False, left, &x, &y); + free(cnt); + putText(dsp, Scr[screen].window, Scr[screen].textgc, + "\n", False, left, &x, &y); } #ifdef USE_SOUND @@ -3150,15 +3123,31 @@ createFontSet(Display * display, char *name) { XFontSet xfs; char *def, **miss; - int miss_count; + int i, n, miss_count; + XFontStruct **font_struct_list; + char **font_name_list; #define DEF_FONTSET2 "fixed,-*-14-*" if ((xfs = XCreateFontSet(display, name, &miss, &miss_count, &def)) == NULL) { - (void) fprintf(stderr, "Could not create FontSet %s\n", name); - if ((xfs = XCreateFontSet(display, DEF_FONTSET2, &miss, &miss_count, &def)) == NULL) - (void) fprintf(stderr, "Could not create FontSet %s\n", DEF_FONTSET2); + (void) fprintf(stderr, "Could not create FontSet %s\n", name); + for (i = 0; i < miss_count; i++) { + (void) fprintf(stderr, "%s\n", miss[i]); + } + if ((xfs = XCreateFontSet(display, DEF_FONTSET2, &miss, &miss_count, &def)) == NULL) { + (void) fprintf(stderr, "Could not create FontSet %s\n", DEF_FONTSET2); + for (i = 0; i < miss_count; i++) { + (void) fprintf(stderr, "%s\n", miss[i]); + } + } + } +#ifdef DEBUG + (void) printf("Selected font list:\n"); + n = XFontsOfFontSet(xfs, &font_struct_list, &font_name_list); + for (i = 0; i < n; i++) { + (void) printf("%s\n", font_name_list[i]); } +#endif return xfs; } #endif @@ -3211,6 +3200,9 @@ main(int argc, char **argv) uid_t ruid; pid_t cmd_pid = 0; + /* Configure gettext localization */ + textdomain("xlock"); + #if defined( SYSV ) || defined( SVR4 ) || ( __VMS_VER >= 70000000 ) static sigset_t old_sigmask; @@ -3438,7 +3430,7 @@ main(int argc, char **argv) minisizeconfigure.height = flags & HeightValue ? h : iconheight; } } - + planfont = XLoadQueryFont(dsp, planfontname); if (planfont == NULL) { (void) fprintf(stderr, "%s: can't find font: %s, using %s...\n",