1 /* Remove, select or merge duplicate translations.
2 Copyright (C) 2001-2007, 2009-2010, 2012 Free Software Foundation, Inc.
3 Written by Bruno Haible <haible@clisp.cons.org>, 2001.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
33 #include "error-progname.h"
35 #include "relocatable.h"
38 #include "read-catalog.h"
40 #include "read-properties.h"
41 #include "read-stringtable.h"
42 #include "write-catalog.h"
44 #include "write-properties.h"
45 #include "write-stringtable.h"
48 #include "propername.h"
51 #define _(str) gettext (str)
54 /* Force output of PO file even if empty. */
57 /* Target encoding. */
58 static const char *to_code;
61 static const struct option long_options[] =
63 { "add-location", no_argument, &line_comment, 1 },
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 { "no-escape", no_argument, NULL, 'e' },
71 { "no-location", no_argument, &line_comment, 0 },
72 { "no-wrap", no_argument, NULL, CHAR_MAX + 2 },
73 { "output-file", required_argument, NULL, 'o' },
74 { "properties-input", no_argument, NULL, 'P' },
75 { "properties-output", no_argument, NULL, 'p' },
76 { "repeated", no_argument, NULL, 'd' },
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 + 3 },
81 { "stringtable-output", no_argument, NULL, CHAR_MAX + 4 },
82 { "style", required_argument, NULL, CHAR_MAX + 6 },
83 { "to-code", required_argument, NULL, 't' },
84 { "unique", no_argument, NULL, 'u' },
85 { "use-first", no_argument, NULL, CHAR_MAX + 1 },
86 { "version", no_argument, NULL, 'V' },
87 { "width", required_argument, NULL, 'w', },
92 /* Forward declaration of local functions. */
93 static void usage (int status)
94 #if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
95 __attribute__ ((noreturn))
101 main (int argc, char **argv)
107 const char *input_file;
108 string_list_ty *file_list;
109 msgdomain_list_ty *result;
110 catalog_input_format_ty input_syntax = &input_format_po;
111 catalog_output_format_ty output_syntax = &output_format_po;
112 bool sort_by_msgid = false;
113 bool sort_by_filepos = false;
115 /* Set program name for messages. */
116 set_program_name (argv[0]);
117 error_print_progname = maybe_print_progname;
119 #ifdef HAVE_SETLOCALE
120 /* Set locale via LC_ALL. */
121 setlocale (LC_ALL, "");
124 /* Set the text message domain. */
125 bindtextdomain (PACKAGE, relocate (LOCALEDIR));
126 bindtextdomain ("bison-runtime", relocate (BISON_LOCALEDIR));
127 textdomain (PACKAGE);
129 /* Ensure that write errors on stdout are detected. */
130 atexit (close_stdout);
132 /* Set default values for variables. */
141 while ((optchar = getopt_long (argc, argv, "dD:eEFhino:pPst:uVw:",
142 long_options, NULL)) != EOF)
145 case '\0': /* Long option. */
154 dir_list_append (optarg);
158 message_print_style_escape (false);
162 message_print_style_escape (true);
166 sort_by_filepos = true;
174 message_print_style_indent ();
182 output_file = optarg;
186 output_syntax = &output_format_properties;
190 input_syntax = &input_format_properties;
194 sort_by_msgid = true;
198 message_print_style_uniforum ();
218 value = strtol (optarg, &endp, 10);
220 message_page_width_set (value);
228 case CHAR_MAX + 2: /* --no-wrap */
229 message_page_width_ignore ();
232 case CHAR_MAX + 3: /* --stringtable-input */
233 input_syntax = &input_format_stringtable;
236 case CHAR_MAX + 4: /* --stringtable-output */
237 output_syntax = &output_format_stringtable;
240 case CHAR_MAX + 5: /* --color */
241 if (handle_color_option (optarg) || color_test_mode)
242 usage (EXIT_FAILURE);
245 case CHAR_MAX + 6: /* --style */
246 handle_style_option (optarg);
250 usage (EXIT_FAILURE);
254 /* Version information requested. */
257 printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
258 /* xgettext: no-wrap */
259 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
260 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
261 This is free software: you are free to change and redistribute it.\n\
262 There is NO WARRANTY, to the extent permitted by law.\n\
265 printf (_("Written by %s.\n"), proper_name ("Bruno Haible"));
269 /* Help is requested. */
271 usage (EXIT_SUCCESS);
273 /* Test whether we have an .po file name as argument. */
276 else if (optind + 1 == argc)
277 input_file = argv[optind];
280 error (EXIT_SUCCESS, 0, _("at most one input file allowed"));
281 usage (EXIT_FAILURE);
284 /* Verify selected options. */
285 if (!line_comment && sort_by_filepos)
286 error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
287 "--no-location", "--sort-by-file");
289 if (sort_by_msgid && sort_by_filepos)
290 error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
291 "--sort-output", "--sort-by-file");
293 /* Determine list of files we have to process: a single file. */
294 file_list = string_list_alloc ();
295 string_list_append (file_list, input_file);
297 /* Read input files, then filter, convert and merge messages. */
298 allow_duplicates = true;
299 result = catenate_msgdomain_list (file_list, input_syntax, to_code);
301 string_list_free (file_list);
303 /* Sorting the list of messages. */
305 msgdomain_list_sort_by_filepos (result);
306 else if (sort_by_msgid)
307 msgdomain_list_sort_by_msgid (result);
309 /* Write the PO file. */
310 msgdomain_list_print (result, output_file, output_syntax, force_po, false);
316 /* Display usage information and exit. */
320 if (status != EXIT_SUCCESS)
321 fprintf (stderr, _("Try '%s --help' for more information.\n"),
326 Usage: %s [OPTION] [INPUTFILE]\n\
329 /* xgettext: no-wrap */
331 Unifies duplicate translations in a translation catalog.\n\
332 Finds duplicate translations of the same message ID. Such duplicates are\n\
333 invalid input for other programs like msgfmt, msgmerge or msgcat. By\n\
334 default, duplicates are merged together. When using the --repeated option,\n\
335 only duplicates are output, and all other messages are discarded. Comments\n\
336 and extracted comments will be cumulated, except that if --use-first is\n\
337 specified, they will be taken from the first translation. File positions\n\
338 will be cumulated. When using the --unique option, duplicates are discarded.\n\
342 Mandatory arguments to long options are mandatory for short options too.\n"));
345 Input file location:\n"));
347 INPUTFILE input PO file\n"));
349 -D, --directory=DIRECTORY add DIRECTORY to list for input files search\n"));
351 If no input file is given or if it is -, standard input is read.\n"));
354 Output file location:\n"));
356 -o, --output-file=FILE write output to specified file\n"));
358 The results are written to standard output if no output file is specified\n\
362 Message selection:\n"));
364 -d, --repeated print only duplicates\n"));
366 -u, --unique print only unique messages, discard duplicates\n"));
369 Input file syntax:\n"));
371 -P, --properties-input input file is in Java .properties syntax\n"));
373 --stringtable-input input file is in NeXTstep/GNUstep .strings syntax\n"));
376 Output details:\n"));
378 -t, --to-code=NAME encoding for output\n"));
380 --use-first use first available translation for each\n\
381 message, don't merge several translations\n"));
383 --color use colors and other text attributes always\n\
384 --color=WHEN use colors and other text attributes if WHEN.\n\
385 WHEN may be 'always', 'never', 'auto', or 'html'.\n"));
387 --style=STYLEFILE specify CSS style rule file for --color\n"));
389 -e, --no-escape do not use C escapes in output (default)\n"));
391 -E, --escape use C escapes in output, no extended chars\n"));
393 --force-po write PO file even if empty\n"));
395 -i, --indent write the .po file using indented style\n"));
397 --no-location do not write '#: filename:line' lines\n"));
399 -n, --add-location generate '#: filename:line' lines (default)\n"));
401 --strict write out strict Uniforum conforming .po file\n"));
403 -p, --properties-output write out a Java .properties file\n"));
405 --stringtable-output write out a NeXTstep/GNUstep .strings file\n"));
407 -w, --width=NUMBER set output page width\n"));
409 --no-wrap do not break long message lines, longer than\n\
410 the output page width, into several lines\n"));
412 -s, --sort-output generate sorted output\n"));
414 -F, --sort-by-file sort output by file location\n"));
417 Informative output:\n"));
419 -h, --help display this help and exit\n"));
421 -V, --version output version information and exit\n"));
423 /* TRANSLATORS: The placeholder indicates the bug-reporting address
424 for this package. Please add _another line_ saying
425 "Report translation bugs to <...>\n" with the address for translation
426 bugs (typically your translation team's web or email address). */
427 fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"),