mirror of
https://salsa.debian.org/dskoll/remind.git
synced 2026-04-17 06:48:47 +02:00
Add the TRANSLATE GENERATE command to generate a skeleton .rem file for localization.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -34,3 +34,4 @@ tests/test.out
|
||||
www/Makefile
|
||||
gmon.out
|
||||
tests/once.timestamp
|
||||
src/xlat.c
|
||||
|
||||
@@ -478,11 +478,13 @@ The \fB\-\-version\fR option causes \fBRemind\fR to print its version number
|
||||
to standard output and then exit.
|
||||
.TP
|
||||
.B \-\-print-errs
|
||||
The \fB\-\-print-errs\fR option causes \fBRemind\fR to print all possible
|
||||
error messages to standard output and then exit. The messages are printed
|
||||
in a format suitable for the first argument of a TRANSLATE command. If
|
||||
you TRANSLATE the error messages, then \fBRemind\fR will use the translated
|
||||
versions when outputting error and warning messages.
|
||||
The \fB\-\-print-errs\fR option causes \fBRemind\fR to print all
|
||||
possible error messages to standard output and then exit. The
|
||||
messages are printed in a format suitable for the first argument of a
|
||||
TRANSLATE command. If you TRANSLATE the error messages, then
|
||||
\fBRemind\fR will use the translated versions when outputting error
|
||||
and warning messages. See also TRANSLATE GENERATE in the section
|
||||
"THE TRANSLATION TABLE".
|
||||
.RS
|
||||
.PP
|
||||
Note that if an untranslated message contains printf-style formatting
|
||||
@@ -5754,13 +5756,40 @@ function, as follows:
|
||||
By using \fBTRANSLATE\fR and \fB_\fR judiciously, you can make your
|
||||
reminder files easy to translate.
|
||||
.PP
|
||||
\fBTRANSLATE\fR has three additional forms: If it is followed
|
||||
\fBTRANSLATE\fR has four additional forms: If it is followed
|
||||
by \fIone\fR quoted string instead of two, then \fBRemind\fR deletes the
|
||||
translation table entry for that string. If it is followed by
|
||||
the keyword \fBDUMP\fR, then \fBRemind\fR dumps all translation table entries
|
||||
to standard output. And if it is followed by \fBCLEAR\fR, then
|
||||
\fBRemind\fR deletes all of the translation table entries.
|
||||
.PP
|
||||
The fourth form, \fBTRANSLATE GENERATE\fR, dumps all of the
|
||||
strings that can be localized (as a series of TRANSLATE commands) to
|
||||
standard output. Strings that are already localized are output
|
||||
with their localization; strings that are not localized are
|
||||
output as:
|
||||
.PP
|
||||
.nf
|
||||
TRANSLATE "untranslated" ""
|
||||
.nf
|
||||
.PP
|
||||
If you want to add a new language, you can obtain a skeleton translation
|
||||
file by running:
|
||||
.PP
|
||||
.nf
|
||||
echo "TRANSLATE GENERATE" | remind -h - > /tmp/skeleton.rem
|
||||
.fi
|
||||
.PP
|
||||
If you have an existing language file that is missing some translations,
|
||||
you can update it by running:
|
||||
.PP
|
||||
.nf
|
||||
(echo INCLUDE mylang.rem; echo TRANSLATE GENERATE) | \\
|
||||
remind -h - > /tmp/mylang-update.rem
|
||||
.fi
|
||||
.PP
|
||||
and then editing \fBmylang-update.rem\fR to add in the missing translations.
|
||||
.PP
|
||||
Note that if you \fBSET\fR various translation-related system
|
||||
variables such as \fB$Monday\fR, \fB$December\fR, \fB$Ago\fR, etc,
|
||||
then \fBRemind\fR \fIalso\fR makes a corresponding translation
|
||||
|
||||
@@ -31,9 +31,11 @@ REMINDSRCS= calendar.c dedupe.c dynbuf.c dorem.c dosubst.c expr.c \
|
||||
hbcal.c init.c main.c md5.c moon.c omit.c queue.c \
|
||||
sort.c token.c trans.c trigger.c userfns.c utils.c var.c
|
||||
|
||||
XLATSRC= xlat.c
|
||||
|
||||
REMINDHDRS=config.h custom.h dynbuf.h err.h globals.h hashtab.h \
|
||||
md5.h protos.h rem2ps.h types.h version.h
|
||||
REMINDOBJS= $(REMINDSRCS:.c=.o)
|
||||
REMINDOBJS= $(REMINDSRCS:.c=.o) $(XLATSRC:.c=.o)
|
||||
|
||||
all: remind rem2ps
|
||||
|
||||
@@ -43,6 +45,13 @@ test: all
|
||||
.c.o:
|
||||
@CC@ -c @CPPFLAGS@ @CFLAGS@ @DEFS@ $(CEXTRA) -DSYSDIR=$(datarootdir)/remind -I. -I$(srcdir) $<
|
||||
|
||||
xlat.c: $(REMINDSRCS)
|
||||
-echo "#include <stddef.h>" > xlat.c
|
||||
-echo "char const *translatables[] = {" >> xlat.c
|
||||
-cat $(REMINDSRCS) | grep 'tr(".*")' *.c | sed -e 's/.*tr."/"/' -e 's/").*/"/' | sort | uniq | sed -e 's/^/ /' -e 's/$$/,/' >> xlat.c
|
||||
-echo " NULL" >> xlat.c
|
||||
-echo "};" >> xlat.c
|
||||
|
||||
$(REMINDOBJS): $(REMINDHDRS)
|
||||
|
||||
rem2ps: rem2ps.o dynbuf.o json.o
|
||||
@@ -80,7 +89,7 @@ install-stripped: install
|
||||
strip $(DESTDIR)$(bindir)/rem2ps || true
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ core *.bak $(PROGS)
|
||||
rm -f *.o *~ core *.bak $(PROGS) $(XLATSRC)
|
||||
|
||||
clobber:
|
||||
rm -f *.o *~ remind rem2ps test.out core *.bak
|
||||
|
||||
@@ -237,3 +237,6 @@ EXTERN int SuppressLRM
|
||||
= 0
|
||||
#endif
|
||||
;
|
||||
|
||||
/* Translatable messages */
|
||||
extern char const *translatables[];
|
||||
|
||||
@@ -273,3 +273,5 @@ int GetTranslatedStringTryingVariants(char const *orig, DynamicBuffer *out);
|
||||
char const *GetErr(int r);
|
||||
char const *tr(char const *s);
|
||||
void print_escaped_string(FILE *fp, char const *s);
|
||||
void GenerateSysvarTranslationTemplates(void);
|
||||
void TranslationTemplate(char const *msg);
|
||||
|
||||
76
src/trans.c
76
src/trans.c
@@ -34,6 +34,65 @@ typedef struct xlat {
|
||||
|
||||
hash_table TranslationTable;
|
||||
|
||||
static XlateItem *FindTranslation(char const *orig);
|
||||
static void print_escaped_string_helper(FILE *fp, char const *s, int esc_for_remind);
|
||||
|
||||
void
|
||||
TranslationTemplate(char const *in)
|
||||
{
|
||||
if (!*in) {
|
||||
return;
|
||||
}
|
||||
if (!strcmp(in, "LANGID")) {
|
||||
return;
|
||||
}
|
||||
|
||||
printf("TRANSLATE ");
|
||||
print_escaped_string_helper(stdout, in, 1);
|
||||
if (FindTranslation(in)) {
|
||||
printf(" ");
|
||||
print_escaped_string_helper(stdout, tr(in), 1);
|
||||
printf("\n");
|
||||
} else {
|
||||
printf(" \"\"\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
GenerateTranslationTemplate(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("# Translation table template\n\n");
|
||||
|
||||
printf("TRANSLATE \"LANGID\" ");
|
||||
print_escaped_string_helper(stdout, tr("LANGID"), 1);
|
||||
printf("\n\n");
|
||||
|
||||
/* Weekday Names */
|
||||
for (i=0; i<7; i++) {
|
||||
TranslationTemplate(DayName[i]);
|
||||
}
|
||||
|
||||
/* Month Names */
|
||||
for (i=0; i<12; i++) {
|
||||
TranslationTemplate(MonthName[i]);
|
||||
}
|
||||
|
||||
/* Translatable system variables */
|
||||
GenerateSysvarTranslationTemplates();
|
||||
|
||||
/* Error messages */
|
||||
for (i=0; i<NumErrs; i++) {
|
||||
TranslationTemplate(ErrMsg[i]);
|
||||
}
|
||||
|
||||
/* Other translatables */
|
||||
for (i=0; translatables[i] != NULL; i++) {
|
||||
TranslationTemplate(translatables[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* AllocateXlateItem - Allocate a new translation item */
|
||||
@@ -113,6 +172,11 @@ ClearTranslationTable(void)
|
||||
void
|
||||
print_escaped_string(FILE *fp, char const *s)
|
||||
{
|
||||
print_escaped_string_helper(fp, s, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
print_escaped_string_helper(FILE *fp, char const *s, int esc_for_remind) {
|
||||
putc('"', fp);
|
||||
while(*s) {
|
||||
switch(*s) {
|
||||
@@ -126,7 +190,11 @@ print_escaped_string(FILE *fp, char const *s)
|
||||
case '"': putc('\\', fp); putc('"', fp); break;
|
||||
case '\\': putc('\\', fp); putc('\\', fp); break;
|
||||
default:
|
||||
putc(*s, fp); break;
|
||||
if (esc_for_remind && *s == '[') {
|
||||
fprintf(fp, "[\"[\"]");
|
||||
} else {
|
||||
putc(*s, fp); break;
|
||||
}
|
||||
}
|
||||
s++;
|
||||
}
|
||||
@@ -353,6 +421,12 @@ DoTranslate(ParsePtr p)
|
||||
ClearTranslationTable();
|
||||
return OK;
|
||||
}
|
||||
if (!StrCmpi(DBufValue(&orig), "generate")) {
|
||||
DBufFree(&orig);
|
||||
if (r) return r;
|
||||
GenerateTranslationTemplate();
|
||||
return OK;
|
||||
}
|
||||
return E_PARSE_ERR;
|
||||
}
|
||||
|
||||
|
||||
23
src/var.c
23
src/var.c
@@ -1239,6 +1239,29 @@ set_components_from_lat_and_long(void)
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateSysvarTranslationTemplates(void)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
char const *msg;
|
||||
for (i=0; i< (int) NUMSYSVARS; i++) {
|
||||
if (SysVarArr[i].type == TRANS_TYPE) {
|
||||
msg = SysVarArr[i].value;
|
||||
/* We've already done month and day names */
|
||||
for (j=0; j<7; j++) {
|
||||
if (!strcmp(msg, DayName[j])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (j=0; j<12; j++) {
|
||||
if (!strcmp(msg, MonthName[j])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
TranslationTemplate(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
void
|
||||
print_sysvar_tokens(void)
|
||||
{
|
||||
|
||||
@@ -641,6 +641,11 @@ set a 9 *
|
||||
set a 9 * ]
|
||||
EOF
|
||||
|
||||
# Translation template generateion
|
||||
../src/remind -h - 1 Feb 2024 <<'EOF' >> ../tests/test.out 2>&1
|
||||
TRANSLATE GENERATE
|
||||
EOF
|
||||
|
||||
# Languages
|
||||
for i in ../include/lang/??.rem ; do
|
||||
../src/remind -r -q "-ii=\"$i\"" ../tests/tstlang.rem 1 Feb 2024 13:34 >> ../tests/test.out 2>&1
|
||||
|
||||
193
tests/test.cmp
193
tests/test.cmp
@@ -24332,6 +24332,199 @@ set a 9 * ]
|
||||
Reminders for Thursday, 1st February, 2024:
|
||||
|
||||
No reminders.
|
||||
# Translation table template
|
||||
|
||||
TRANSLATE "LANGID" "en"
|
||||
|
||||
TRANSLATE "Monday" ""
|
||||
TRANSLATE "Tuesday" ""
|
||||
TRANSLATE "Wednesday" ""
|
||||
TRANSLATE "Thursday" ""
|
||||
TRANSLATE "Friday" ""
|
||||
TRANSLATE "Saturday" ""
|
||||
TRANSLATE "Sunday" ""
|
||||
TRANSLATE "January" ""
|
||||
TRANSLATE "February" ""
|
||||
TRANSLATE "March" ""
|
||||
TRANSLATE "April" ""
|
||||
TRANSLATE "May" ""
|
||||
TRANSLATE "June" ""
|
||||
TRANSLATE "July" ""
|
||||
TRANSLATE "August" ""
|
||||
TRANSLATE "September" ""
|
||||
TRANSLATE "October" ""
|
||||
TRANSLATE "November" ""
|
||||
TRANSLATE "December" ""
|
||||
TRANSLATE "ago" ""
|
||||
TRANSLATE "am" ""
|
||||
TRANSLATE "and" ""
|
||||
TRANSLATE "Ok" ""
|
||||
TRANSLATE "Missing ']'" ""
|
||||
TRANSLATE "Missing quote" ""
|
||||
TRANSLATE "Expression too complex" ""
|
||||
TRANSLATE "Missing ')'" ""
|
||||
TRANSLATE "Undefined function" ""
|
||||
TRANSLATE "Illegal character" ""
|
||||
TRANSLATE "Expecting binary operator" ""
|
||||
TRANSLATE "Out of memory" ""
|
||||
TRANSLATE "Ill-formed number" ""
|
||||
TRANSLATE "Can't coerce" ""
|
||||
TRANSLATE "Type mismatch" ""
|
||||
TRANSLATE "Date overflow" ""
|
||||
TRANSLATE "Division by zero" ""
|
||||
TRANSLATE "Undefined variable" ""
|
||||
TRANSLATE "Unexpected end of line" ""
|
||||
TRANSLATE "Unexpected end of file" ""
|
||||
TRANSLATE "I/O error" ""
|
||||
TRANSLATE "Internal error" ""
|
||||
TRANSLATE "Bad date specification" ""
|
||||
TRANSLATE "Not enough arguments" ""
|
||||
TRANSLATE "Too many arguments" ""
|
||||
TRANSLATE "Ill-formed time" ""
|
||||
TRANSLATE "Number too high" ""
|
||||
TRANSLATE "Number too low" ""
|
||||
TRANSLATE "Can't open file" ""
|
||||
TRANSLATE "INCLUDE nested too deeply (max. 9)" ""
|
||||
TRANSLATE "Parse error" ""
|
||||
TRANSLATE "Can't compute trigger" ""
|
||||
TRANSLATE "Too many nested IFs" ""
|
||||
TRANSLATE "ELSE with no matching IF" ""
|
||||
TRANSLATE "ENDIF with no matching IF" ""
|
||||
TRANSLATE "Can't OMIT every weekday" ""
|
||||
TRANSLATE "Extraneous token(s) on line" ""
|
||||
TRANSLATE "POP-OMIT-CONTEXT without matching PUSH-OMIT-CONTEXT" ""
|
||||
TRANSLATE "RUN disabled" ""
|
||||
TRANSLATE "Domain error" ""
|
||||
TRANSLATE "Invalid identifier" ""
|
||||
TRANSLATE "Too many recursive function calls" ""
|
||||
TRANSLATE "Cannot modify system variable" ""
|
||||
TRANSLATE "C library function can't represent date/time" ""
|
||||
TRANSLATE "Attempt to redefine built-in function" ""
|
||||
TRANSLATE "Can't nest function definition in expression" ""
|
||||
TRANSLATE "Must fully specify date to use repeat factor" ""
|
||||
TRANSLATE "Year specified twice" ""
|
||||
TRANSLATE "Month specified twice" ""
|
||||
TRANSLATE "Day specified twice" ""
|
||||
TRANSLATE "Unknown token" ""
|
||||
TRANSLATE "Must specify month in OMIT command" ""
|
||||
TRANSLATE "Too many full OMITs (max. 1000)" ""
|
||||
TRANSLATE "Warning: PUSH-OMIT-CONTEXT without matching POP-OMIT-CONTEXT" ""
|
||||
TRANSLATE "Error reading" ""
|
||||
TRANSLATE "Expecting end-of-line" ""
|
||||
TRANSLATE "Invalid Hebrew date" ""
|
||||
TRANSLATE "iif(): odd number of arguments required" ""
|
||||
TRANSLATE "Warning: Missing ENDIF" ""
|
||||
TRANSLATE "Expecting comma" ""
|
||||
TRANSLATE "Weekday specified twice" ""
|
||||
TRANSLATE "Only use one of BEFORE, AFTER or SKIP" ""
|
||||
TRANSLATE "Can't nest MSG, MSF, RUN, etc. in expression" ""
|
||||
TRANSLATE "Repeat value specified twice" ""
|
||||
TRANSLATE "Delta value specified twice" ""
|
||||
TRANSLATE "Back value specified twice" ""
|
||||
TRANSLATE "ONCE keyword used twice. (Hah.)" ""
|
||||
TRANSLATE "Expecting time after AT" ""
|
||||
TRANSLATE "THROUGH/UNTIL keyword used twice" ""
|
||||
TRANSLATE "Incomplete date specification" ""
|
||||
TRANSLATE "FROM/SCANFROM keyword used twice" ""
|
||||
TRANSLATE "Variable" ""
|
||||
TRANSLATE "Value" ""
|
||||
TRANSLATE "*UNDEFINED*" ""
|
||||
TRANSLATE "Entering UserFN" ""
|
||||
TRANSLATE "Leaving UserFN" ""
|
||||
TRANSLATE "Expired" ""
|
||||
TRANSLATE "fork() failed - can't do queued reminders" ""
|
||||
TRANSLATE "Can't access file" ""
|
||||
TRANSLATE "Illegal system date: Year is less than %d\n" ""
|
||||
TRANSLATE "Unknown debug flag '%c'\n" ""
|
||||
TRANSLATE "Unknown option '%c'\n" ""
|
||||
TRANSLATE "Unknown user '%s'\n" ""
|
||||
TRANSLATE "Could not change gid to %d\n" ""
|
||||
TRANSLATE "Could not change uid to %d\n" ""
|
||||
TRANSLATE "Out of memory for environment\n" ""
|
||||
TRANSLATE "Missing '=' sign" ""
|
||||
TRANSLATE "Missing variable name" ""
|
||||
TRANSLATE "Missing expression" ""
|
||||
TRANSLATE "Remind: '-i' option: %s\n" ""
|
||||
TRANSLATE "No reminders." ""
|
||||
TRANSLATE "%d reminder(s) queued for later today.\n" ""
|
||||
TRANSLATE "Expecting number" ""
|
||||
TRANSLATE "Undefined WARN function" ""
|
||||
TRANSLATE "Can't convert between time zones" ""
|
||||
TRANSLATE "No files matching *.rem" ""
|
||||
TRANSLATE "String too long" ""
|
||||
TRANSLATE "Time specified twice" ""
|
||||
TRANSLATE "Cannot specify DURATION without specifying AT" ""
|
||||
TRANSLATE "Expecting weekday name" ""
|
||||
TRANSLATE "Duplicate argument name" ""
|
||||
TRANSLATE "Expression evaluation is disabled" ""
|
||||
TRANSLATE "Time limit for expression evaluation exceeded" ""
|
||||
TRANSLATE " %s(%d): ["["]#%d] %s function `%s'" ""
|
||||
TRANSLATE "%s function `%s' defined at %s:%d does not use its argument" ""
|
||||
TRANSLATE "%s function `%s' defined at %s:%d should take 1 argument but actually takes %d" ""
|
||||
TRANSLATE "%s is deprecated; use %s instead" ""
|
||||
TRANSLATE "%s(%d): IF without ENDIF\n" ""
|
||||
TRANSLATE "(Security note: $RunOff variable tested.)" ""
|
||||
TRANSLATE "Accepting \"%s\" for $Latitude/$Longitude, but you should use the \"C\" locale decimal separator \".\" instead" ""
|
||||
TRANSLATE "Caching directory `%s' listing\n" ""
|
||||
TRANSLATE "Caching file `%s' in memory\n" ""
|
||||
TRANSLATE "Called from" ""
|
||||
TRANSLATE "Cannot open `%s' for writing: %s\n" ""
|
||||
TRANSLATE "Cannot stat %s - not running as daemon!\n" ""
|
||||
TRANSLATE "Cannot use AT clause in multitrig() function" ""
|
||||
TRANSLATE "Do not use ["["]] around expression in SET command" ""
|
||||
TRANSLATE "Error: THROUGH date earlier than start date" ""
|
||||
TRANSLATE "Executing `%s' for INCLUDECMD and caching as `%s'\n" ""
|
||||
TRANSLATE "Found cached directory listing for `%s'\n" ""
|
||||
TRANSLATE "Function `%s' defined at %s:%d should take %d argument%s, but actually takes %d" ""
|
||||
TRANSLATE "Function `%s' redefined (previously defined at %s:%d)" ""
|
||||
TRANSLATE "GetValidHebDate: Bad adarbehave value %d" ""
|
||||
TRANSLATE "In" ""
|
||||
TRANSLATE "Missing REM type; assuming MSG" ""
|
||||
TRANSLATE "No Adar A in %d" ""
|
||||
TRANSLATE "No substition function `%s' defined" ""
|
||||
TRANSLATE "Not setting $OnceFile: Already processed a reminder with a ONCE clause" ""
|
||||
TRANSLATE "OMIT: UNTIL not allowed; did you mean THROUGH?" ""
|
||||
TRANSLATE "POP-OMIT-CONTEXT at %s:%d matches PUSH-OMIT-CONTEXT in different file: %s:%d" ""
|
||||
TRANSLATE "Reading `%s': Found in cache\n" ""
|
||||
TRANSLATE "Reading `%s': Opening file on disk\n" ""
|
||||
TRANSLATE "Reading `-': Reading stdin\n" ""
|
||||
TRANSLATE "Reading command `%s': Found in cache\n" ""
|
||||
TRANSLATE "SATISFY: constant 0 will never be true" ""
|
||||
TRANSLATE "SATISFY: constant \"\" will never be true" ""
|
||||
TRANSLATE "SATISFY: expression has no reference to trigdate() or $T..." ""
|
||||
TRANSLATE "SECURITY: Won't read non-root-owned file or directory when running as root!\n" ""
|
||||
TRANSLATE "SECURITY: Won't read world-writable file or directory!\n" ""
|
||||
TRANSLATE "Scanning directory `%s' for *.rem files\n" ""
|
||||
TRANSLATE "Undefined %s function: `%s'" ""
|
||||
TRANSLATE "Unmatched PUSH-OMIT-CONTEXT at %s(%d)" ""
|
||||
TRANSLATE "Unrecognized command; interpreting as REM" ""
|
||||
TRANSLATE "Warning: Function name `%s...' truncated to `%s'" ""
|
||||
TRANSLATE "Warning: OMIT is ignored if you use OMITFUNC" ""
|
||||
TRANSLATE "Warning: SCANFROM is ignored in two-argument form of evaltrig()" ""
|
||||
TRANSLATE "Warning: UNTIL/THROUGH date earlier than FROM date" ""
|
||||
TRANSLATE "Warning: UNTIL/THROUGH date earlier than SCANFROM date" ""
|
||||
TRANSLATE "Warning: UNTIL/THROUGH date earlier than start date" ""
|
||||
TRANSLATE "Warning: Unable to save ONCE timestamp to %s: %s" ""
|
||||
TRANSLATE "Warning: Unterminated %%(...) substitution sequence" ""
|
||||
TRANSLATE "Warning: Unterminated %%{...} substitution sequence" ""
|
||||
TRANSLATE "Warning: Useless use of UNTIL with fully-specified date and no *rep" ""
|
||||
TRANSLATE "Warning: Variable name `%.*s...' truncated to `%.*s'" ""
|
||||
TRANSLATE "You have OMITted everything! The space-time continuum is at risk." ""
|
||||
TRANSLATE "am" ""
|
||||
TRANSLATE "at" ""
|
||||
TRANSLATE "did you mean" ""
|
||||
TRANSLATE "from now" ""
|
||||
TRANSLATE "here" ""
|
||||
TRANSLATE "hour" ""
|
||||
TRANSLATE "minute" ""
|
||||
TRANSLATE "now" ""
|
||||
TRANSLATE "on" ""
|
||||
TRANSLATE "pm" ""
|
||||
TRANSLATE "psmoon() is deprecated; use SPECIAL MOON instead." ""
|
||||
TRANSLATE "psshade() is deprecated; use SPECIAL SHADE instead." ""
|
||||
TRANSLATE "remaining call frames omitted" ""
|
||||
TRANSLATE "today" ""
|
||||
TRANSLATE "was" ""
|
||||
Agenda pel dijous, 1 de febrer de 2024:
|
||||
|
||||
Language: ca
|
||||
|
||||
Reference in New Issue
Block a user