1 /* Creates an English translation catalog.
2 Copyright (C) 2001-2007, 2009-2010, 2012, 2014, 2016, 2018-2020 Free Software
3 Foundation, Inc.
4 Written by Bruno Haible <haible@clisp.cons.org>, 2001.
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include <getopt.h>
25 #include <limits.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <locale.h>
29
30 #include <textstyle.h>
31
32 #include "noreturn.h"
33 #include "closeout.h"
34 #include "dir-list.h"
35 #include "error.h"
36 #include "error-progname.h"
37 #include "progname.h"
38 #include "relocatable.h"
39 #include "basename-lgpl.h"
40 #include "message.h"
41 #include "read-catalog.h"
42 #include "read-po.h"
43 #include "read-properties.h"
44 #include "read-stringtable.h"
45 #include "msgl-english.h"
46 #include "msgl-header.h"
47 #include "write-catalog.h"
48 #include "write-po.h"
49 #include "write-properties.h"
50 #include "write-stringtable.h"
51 #include "propername.h"
52 #include "gettext.h"
53
54 #define _(str) gettext (str)
55
56
57 /* Force output of PO file even if empty. */
58 static int force_po;
59
60 /* Long options. */
61 static const struct option long_options[] =
62 {
63 { "add-location", optional_argument, NULL, 'n' },
64 { "color", optional_argument, NULL, CHAR_MAX + 5 },
65 { "directory", required_argument, NULL, 'D' },
66 { "escape", no_argument, NULL, 'E' },
67 { "force-po", no_argument, &force_po, 1 },
68 { "help", no_argument, NULL, 'h' },
69 { "indent", no_argument, NULL, 'i' },
70 { "lang", required_argument, NULL, CHAR_MAX + 4 },
71 { "no-escape", no_argument, NULL, 'e' },
72 { "no-location", no_argument, NULL, CHAR_MAX + 7 },
73 { "no-wrap", no_argument, NULL, CHAR_MAX + 1 },
74 { "output-file", required_argument, NULL, 'o' },
75 { "properties-input", no_argument, NULL, 'P' },
76 { "properties-output", no_argument, NULL, 'p' },
77 { "sort-by-file", no_argument, NULL, 'F' },
78 { "sort-output", no_argument, NULL, 's' },
79 { "strict", no_argument, NULL, 'S' },
80 { "stringtable-input", no_argument, NULL, CHAR_MAX + 2 },
81 { "stringtable-output", no_argument, NULL, CHAR_MAX + 3 },
82 { "style", required_argument, NULL, CHAR_MAX + 6 },
83 { "version", no_argument, NULL, 'V' },
84 { "width", required_argument, NULL, 'w' },
85 { NULL, 0, NULL, 0 }
86 };
87
88
89 /* Forward declaration of local functions. */
90 _GL_NORETURN_FUNC static void usage (int status);
91
92
93 int
main(int argc,char ** argv)94 main (int argc, char **argv)
95 {
96 int opt;
97 bool do_help;
98 bool do_version;
99 char *output_file;
100 msgdomain_list_ty *result;
101 catalog_input_format_ty input_syntax = &input_format_po;
102 catalog_output_format_ty output_syntax = &output_format_po;
103 bool sort_by_filepos = false;
104 bool sort_by_msgid = false;
105 /* Language (ISO-639 code) and optional territory (ISO-3166 code). */
106 const char *catalogname = NULL;
107
108 /* Set program name for messages. */
109 set_program_name (argv[0]);
110 error_print_progname = maybe_print_progname;
111
112 /* Set locale via LC_ALL. */
113 setlocale (LC_ALL, "");
114
115 /* Set the text message domain. */
116 bindtextdomain (PACKAGE, relocate (LOCALEDIR));
117 bindtextdomain ("bison-runtime", relocate (BISON_LOCALEDIR));
118 textdomain (PACKAGE);
119
120 /* Ensure that write errors on stdout are detected. */
121 atexit (close_stdout);
122
123 /* Set default values for variables. */
124 do_help = false;
125 do_version = false;
126 output_file = NULL;
127
128 while ((opt = getopt_long (argc, argv,
129 "D:eEFhin:o:pPsVw:",
130 long_options, NULL)) != EOF)
131 switch (opt)
132 {
133 case '\0': /* Long option. */
134 break;
135
136 case 'D':
137 dir_list_append (optarg);
138 break;
139
140 case 'e':
141 message_print_style_escape (false);
142 break;
143
144 case 'E':
145 message_print_style_escape (true);
146 break;
147
148 case 'F':
149 sort_by_filepos = true;
150 break;
151
152 case 'h':
153 do_help = true;
154 break;
155
156 case 'i':
157 message_print_style_indent ();
158 break;
159
160 case 'n':
161 if (handle_filepos_comment_option (optarg))
162 usage (EXIT_FAILURE);
163 break;
164
165 case 'o':
166 output_file = optarg;
167 break;
168
169 case 'p':
170 output_syntax = &output_format_properties;
171 break;
172
173 case 'P':
174 input_syntax = &input_format_properties;
175 break;
176
177 case 's':
178 sort_by_msgid = true;
179 break;
180
181 case 'S':
182 message_print_style_uniforum ();
183 break;
184
185 case 'V':
186 do_version = true;
187 break;
188
189 case 'w':
190 {
191 int value;
192 char *endp;
193 value = strtol (optarg, &endp, 10);
194 if (endp != optarg)
195 message_page_width_set (value);
196 }
197 break;
198
199 case CHAR_MAX + 1: /* --no-wrap */
200 message_page_width_ignore ();
201 break;
202
203 case CHAR_MAX + 2: /* --stringtable-input */
204 input_syntax = &input_format_stringtable;
205 break;
206
207 case CHAR_MAX + 3: /* --stringtable-output */
208 output_syntax = &output_format_stringtable;
209 break;
210
211 case CHAR_MAX + 4: /* --lang */
212 catalogname = optarg;
213 break;
214
215 case CHAR_MAX + 5: /* --color */
216 if (handle_color_option (optarg) || color_test_mode)
217 usage (EXIT_FAILURE);
218 break;
219
220 case CHAR_MAX + 6: /* --style */
221 handle_style_option (optarg);
222 break;
223
224 case CHAR_MAX + 7: /* --no-location */
225 message_print_style_filepos (filepos_comment_none);
226 break;
227
228 default:
229 usage (EXIT_FAILURE);
230 break;
231 }
232
233 /* Version information is requested. */
234 if (do_version)
235 {
236 printf ("%s (GNU %s) %s\n", last_component (program_name),
237 PACKAGE, VERSION);
238 /* xgettext: no-wrap */
239 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
240 License GPLv3+: GNU GPL version 3 or later <%s>\n\
241 This is free software: you are free to change and redistribute it.\n\
242 There is NO WARRANTY, to the extent permitted by law.\n\
243 "),
244 "2001-2020", "https://gnu.org/licenses/gpl.html");
245 printf (_("Written by %s.\n"), proper_name ("Bruno Haible"));
246 exit (EXIT_SUCCESS);
247 }
248
249 /* Help is requested. */
250 if (do_help)
251 usage (EXIT_SUCCESS);
252
253 /* Test whether we have an .po file name as argument. */
254 if (optind >= argc)
255 {
256 error (EXIT_SUCCESS, 0, _("no input file given"));
257 usage (EXIT_FAILURE);
258 }
259 if (optind + 1 != argc)
260 {
261 error (EXIT_SUCCESS, 0, _("exactly one input file required"));
262 usage (EXIT_FAILURE);
263 }
264
265 /* Verify selected options. */
266 if (sort_by_msgid && sort_by_filepos)
267 error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
268 "--sort-output", "--sort-by-file");
269
270 /* Read input file. */
271 result = read_catalog_file (argv[optind], input_syntax);
272
273 /* Add English translations. */
274 result = msgdomain_list_english (result);
275
276 /* Sort the results. */
277 if (sort_by_filepos)
278 msgdomain_list_sort_by_filepos (result);
279 else if (sort_by_msgid)
280 msgdomain_list_sort_by_msgid (result);
281
282 /* Set the Language field in the header. */
283 if (catalogname != NULL)
284 msgdomain_list_set_header_field (result, "Language:", catalogname);
285
286 /* Write the merged message list out. */
287 msgdomain_list_print (result, output_file, output_syntax, force_po, false);
288
289 exit (EXIT_SUCCESS);
290 }
291
292
293 /* Display usage information and exit. */
294 static void
usage(int status)295 usage (int status)
296 {
297 if (status != EXIT_SUCCESS)
298 fprintf (stderr, _("Try '%s --help' for more information.\n"),
299 program_name);
300 else
301 {
302 printf (_("\
303 Usage: %s [OPTION] INPUTFILE\n\
304 "), program_name);
305 printf ("\n");
306 /* xgettext: no-wrap */
307 printf (_("\
308 Creates an English translation catalog. The input file is the last\n\
309 created English PO file, or a PO Template file (generally created by\n\
310 xgettext). Untranslated entries are assigned a translation that is\n\
311 identical to the msgid.\n\
312 "));
313 printf ("\n");
314 printf (_("\
315 Mandatory arguments to long options are mandatory for short options too.\n"));
316 printf ("\n");
317 printf (_("\
318 Input file location:\n"));
319 printf (_("\
320 INPUTFILE input PO or POT file\n"));
321 printf (_("\
322 -D, --directory=DIRECTORY add DIRECTORY to list for input files search\n"));
323 printf (_("\
324 If input file is -, standard input is read.\n"));
325 printf ("\n");
326 printf (_("\
327 Output file location:\n"));
328 printf (_("\
329 -o, --output-file=FILE write output to specified file\n"));
330 printf (_("\
331 The results are written to standard output if no output file is specified\n\
332 or if it is -.\n"));
333 printf ("\n");
334 printf (_("\
335 Input file syntax:\n"));
336 printf (_("\
337 -P, --properties-input input file is in Java .properties syntax\n"));
338 printf (_("\
339 --stringtable-input input file is in NeXTstep/GNUstep .strings syntax\n"));
340 printf ("\n");
341 printf (_("\
342 Output details:\n"));
343 printf (_("\
344 --lang=CATALOGNAME set 'Language' field in the header entry\n"));
345 printf (_("\
346 --color use colors and other text attributes always\n\
347 --color=WHEN use colors and other text attributes if WHEN.\n\
348 WHEN may be 'always', 'never', 'auto', or 'html'.\n"));
349 printf (_("\
350 --style=STYLEFILE specify CSS style rule file for --color\n"));
351 printf (_("\
352 -e, --no-escape do not use C escapes in output (default)\n"));
353 printf (_("\
354 -E, --escape use C escapes in output, no extended chars\n"));
355 printf (_("\
356 --force-po write PO file even if empty\n"));
357 printf (_("\
358 -i, --indent indented output style\n"));
359 printf (_("\
360 --no-location suppress '#: filename:line' lines\n"));
361 printf (_("\
362 -n, --add-location preserve '#: filename:line' lines (default)\n"));
363 printf (_("\
364 --strict strict Uniforum output style\n"));
365 printf (_("\
366 -p, --properties-output write out a Java .properties file\n"));
367 printf (_("\
368 --stringtable-output write out a NeXTstep/GNUstep .strings file\n"));
369 printf (_("\
370 -w, --width=NUMBER set output page width\n"));
371 printf (_("\
372 --no-wrap do not break long message lines, longer than\n\
373 the output page width, into several lines\n"));
374 printf (_("\
375 -s, --sort-output generate sorted output\n"));
376 printf (_("\
377 -F, --sort-by-file sort output by file location\n"));
378 printf ("\n");
379 printf (_("\
380 Informative output:\n"));
381 printf (_("\
382 -h, --help display this help and exit\n"));
383 printf (_("\
384 -V, --version output version information and exit\n"));
385 printf ("\n");
386 /* TRANSLATORS: The first placeholder is the web address of the Savannah
387 project of this package. The second placeholder is the bug-reporting
388 email address for this package. Please add _another line_ saying
389 "Report translation bugs to <...>\n" with the address for translation
390 bugs (typically your translation team's web or email address). */
391 printf(_("\
392 Report bugs in the bug tracker at <%s>\n\
393 or by email to <%s>.\n"),
394 "https://savannah.gnu.org/projects/gettext",
395 "bug-gettext@gnu.org");
396 }
397
398 exit (status);
399 }
400