]> git.ipfire.org Git - thirdparty/cups.git/blob - locale/po2strings.c
Add ellipsis to "Looking for printer" message.
[thirdparty/cups.git] / locale / po2strings.c
1 /*
2 * "$Id$"
3 *
4 * Convert a GNU gettext .po file to an Apple .strings file.
5 *
6 * Copyright 2007-2015 by Apple Inc.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
11 * which should have been included with this file. If this file is
12 * file is missing or damaged, see the license at "http://www.cups.org/".
13 *
14 * Usage:
15 *
16 * po2strings filename.strings filename.po
17 *
18 * Compile with:
19 *
20 * gcc -o po2strings po2strings.c `cups-config --libs`
21 */
22
23 #include <cups/cups-private.h>
24
25
26 /*
27 * The .strings file format is simple:
28 *
29 * // comment
30 * "msgid" = "msgstr";
31 *
32 * The GNU gettext .po format is also fairly simple:
33 *
34 * #. comment
35 * msgid "some text"
36 * msgstr "localized text"
37 *
38 * The comment, msgid, and msgstr text can span multiple lines using the form:
39 *
40 * #. comment
41 * #. more comments
42 * msgid ""
43 * "some long text"
44 * msgstr ""
45 * "localized text spanning "
46 * "multiple lines"
47 *
48 * Both the msgid and msgstr strings use standard C quoting for special
49 * characters like newline and the double quote character.
50 */
51
52 static char *normalize_string(const char *idstr, char *buffer, size_t bufsize);
53
54
55 /*
56 * main() - Convert .po file to .strings.
57 */
58
59 int /* O - Exit code */
60 main(int argc, /* I - Number of command-line args */
61 char *argv[]) /* I - Command-line arguments */
62 {
63 int i; /* Looping var */
64 const char *pofile, /* .po filename */
65 *stringsfile; /* .strings filename */
66 cups_file_t *po, /* .po file */
67 *strings; /* .strings file */
68 char s[4096], /* String buffer */
69 *ptr, /* Pointer into buffer */
70 *temp, /* New string */
71 *msgid, /* msgid string */
72 *msgstr, /* msgstr string */
73 normalized[8192];/* Normalized msgid string */
74 size_t length; /* Length of combined strings */
75 int use_msgid; /* Use msgid strings for msgstr? */
76
77
78 /*
79 * Process command-line arguments...
80 */
81
82 pofile = NULL;
83 stringsfile = NULL;
84 use_msgid = 0;
85
86 for (i = 1; i < argc; i ++)
87 {
88 if (!strcmp(argv[i], "-m"))
89 use_msgid = 1;
90 else if (argv[i][0] == '-')
91 {
92 puts("Usage: po2strings [-m] filename.po filename.strings");
93 return (1);
94 }
95 else if (!pofile)
96 pofile = argv[i];
97 else if (!stringsfile)
98 stringsfile = argv[i];
99 else
100 {
101 puts("Usage: po2strings [-m] filename.po filename.strings");
102 return (1);
103 }
104 }
105
106 if (!pofile || !stringsfile)
107 {
108 puts("Usage: po2strings [-m] filename.po filename.strings");
109 return (1);
110 }
111
112 /*
113 * Read strings from the .po file and write to the .strings file...
114 */
115
116 if ((po = cupsFileOpen(pofile, "r")) == NULL)
117 {
118 perror(pofile);
119 return (1);
120 }
121
122 if ((strings = cupsFileOpen(stringsfile, "w")) == NULL)
123 {
124 perror(stringsfile);
125 cupsFileClose(po);
126 return (1);
127 }
128
129 msgid = msgstr = NULL;
130
131 while (cupsFileGets(po, s, sizeof(s)) != NULL)
132 {
133 if (s[0] == '#' && s[1] == '.')
134 {
135 /*
136 * Copy comment string...
137 */
138
139 if (msgid && msgstr)
140 {
141 /*
142 * First output the last localization string...
143 */
144
145 if (*msgid)
146 cupsFilePrintf(strings, "\"%s\" = \"%s\";\n", msgid,
147 (use_msgid || !*msgstr) ? msgid : msgstr);
148
149 free(msgid);
150 free(msgstr);
151 msgid = msgstr = NULL;
152 }
153
154 cupsFilePrintf(strings, "//%s\n", s + 2);
155 }
156 else if (s[0] == '#' || !s[0])
157 {
158 /*
159 * Skip blank and file comment lines...
160 */
161
162 continue;
163 }
164 else
165 {
166 /*
167 * Strip the trailing quote...
168 */
169
170 if ((ptr = strrchr(s, '\"')) == NULL)
171 continue;
172
173 *ptr = '\0';
174
175 /*
176 * Find start of value...
177 */
178
179 if ((ptr = strchr(s, '\"')) == NULL)
180 continue;
181
182 ptr ++;
183
184 /*
185 * Create or add to a message...
186 */
187
188 if (!strncmp(s, "msgid", 5))
189 {
190 /*
191 * Output previous message as needed...
192 */
193
194 if (msgid && msgstr)
195 {
196 if (*msgid)
197 cupsFilePrintf(strings, "\"%s\" = \"%s\";\n", msgid, normalize_string((use_msgid || !*msgstr) ? msgid : msgstr, normalized, sizeof(normalized)));
198 }
199
200 if (msgid)
201 free(msgid);
202
203 if (msgstr)
204 free(msgstr);
205
206 msgid = strdup(ptr);
207 msgstr = NULL;
208 }
209 else if (s[0] == '\"' && (msgid || msgstr))
210 {
211 /*
212 * Append to current string...
213 */
214
215 size_t ptrlen = strlen(ptr); /* Length of string */
216
217 length = strlen(msgstr ? msgstr : msgid);
218
219 if ((temp = realloc(msgstr ? msgstr : msgid,
220 length + ptrlen + 1)) == NULL)
221 {
222 free(msgid);
223 if (msgstr)
224 free(msgstr);
225 perror("Unable to allocate string");
226 return (1);
227 }
228
229 if (msgstr)
230 {
231 /*
232 * Copy the new portion to the end of the msgstr string - safe
233 * to use strcpy because the buffer is allocated to the correct
234 * size...
235 */
236
237 msgstr = temp;
238
239 memcpy(msgstr + length, ptr, ptrlen + 1);
240 }
241 else
242 {
243 /*
244 * Copy the new portion to the end of the msgid string - safe
245 * to use strcpy because the buffer is allocated to the correct
246 * size...
247 */
248
249 msgid = temp;
250
251 memcpy(msgid + length, ptr, ptrlen + 1);
252 }
253 }
254 else if (!strncmp(s, "msgstr", 6) && msgid)
255 {
256 /*
257 * Set the string...
258 */
259
260 if (msgstr)
261 free(msgstr);
262
263 if ((msgstr = strdup(ptr)) == NULL)
264 {
265 free(msgid);
266 perror("Unable to allocate msgstr");
267 return (1);
268 }
269 }
270 }
271 }
272
273 if (msgid && msgstr)
274 {
275 if (*msgid)
276 cupsFilePrintf(strings, "\"%s\" = \"%s\";\n", msgid, normalize_string((use_msgid || !*msgstr) ? msgid : msgstr, normalized, sizeof(normalized)));
277 }
278
279 if (msgid)
280 free(msgid);
281
282 if (msgstr)
283 free(msgstr);
284
285 cupsFileClose(po);
286 cupsFileClose(strings);
287
288 return (0);
289 }
290
291
292 /*
293 * 'normalize_string()' - Normalize a msgid string.
294 *
295 * This function converts ASCII ellipsis and double quotes to their Unicode
296 * counterparts.
297 */
298
299 static char * /* O - Normalized string */
300 normalize_string(const char *idstr, /* I - msgid string */
301 char *buffer, /* I - Normalized string buffer */
302 size_t bufsize) /* I - Size of string buffer */
303 {
304 char *bufptr = buffer, /* Pointer into buffer */
305 *bufend = buffer + bufsize - 3; /* End of buffer */
306 int quote = 0; /* Quote direction */
307
308
309 while (*idstr && bufptr < bufend)
310 {
311 if (*idstr == '.' && idstr[1] == '.' && idstr[2] == '.')
312 {
313 /*
314 * Convert "..." to Unicode ellipsis...
315 */
316
317 *bufptr++ = (char)0xE2;
318 *bufptr++ = (char)0x80;
319 *bufptr++ = (char)0xA6;
320 idstr += 2;
321 }
322 else if (*idstr == '\"')
323 {
324 if (quote)
325 {
326 /*
327 * Convert " to right quote.
328 */
329
330 *bufptr++ = (char)0xE2;
331 *bufptr++ = (char)0x80;
332 *bufptr++ = (char)0x9D;
333 }
334 else
335 {
336 /*
337 * Convert " to left quote.
338 */
339
340 *bufptr++ = (char)0xE2;
341 *bufptr++ = (char)0x80;
342 *bufptr++ = (char)0x9C;
343 }
344
345 quote = !quote;
346 }
347 else
348 *bufptr++ = *idstr;
349
350 idstr ++;
351 }
352
353 *bufptr = '\0';
354
355 return (buffer);
356 }
357
358
359 /*
360 * End of "$Id$".
361 */