]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/localize.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / localize.c
1 /*
2 * "$Id: localize.c 6686 2007-07-16 23:11:59Z mike $"
3 *
4 * PPD custom option routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * PostScript is a trademark of Adobe Systems, Inc.
16 *
17 * This code and any derivative of it may be used and distributed
18 * freely under the terms of the GNU General Public License when
19 * used with GNU Ghostscript or its derivatives. Use of the code
20 * (or any derivative of it) with software other than GNU
21 * GhostScript (or its derivatives) is governed by the CUPS license
22 * agreement.
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * ppdLocalize() - Localize the PPD file to the current locale.
29 * ppdLocalizeIPPReason() - Get the localized version of a cupsIPPReason
30 * attribute.
31 * ppd_ll_CC() - Get the current locale names.
32 * ppd_localized_attr() - Find a localized attribute.
33 */
34
35 /*
36 * Include necessary headers.
37 */
38
39 #include "globals.h"
40 #include "debug.h"
41
42
43 /*
44 * Local functions...
45 */
46
47 static void ppd_ll_CC(char *ll_CC, char *ll);
48 static ppd_attr_t *ppd_localized_attr(ppd_file_t *ppd,
49 const char *keyword,
50 const char *spec, const char *ll_CC,
51 const char *ll);
52
53
54 /*
55 * 'ppdLocalize()' - Localize the PPD file to the current locale.
56 *
57 * All groups, options, and choices are localized, as are ICC profile
58 * descriptions, printer presets, and custom option parameters. Each
59 * localized string uses the UTF-8 character encoding.
60 *
61 * @since CUPS 1.2@
62 */
63
64 int /* O - 0 on success, -1 on error */
65 ppdLocalize(ppd_file_t *ppd) /* I - PPD file */
66 {
67 int i, j, k; /* Looping vars */
68 ppd_group_t *group; /* Current group */
69 ppd_option_t *option; /* Current option */
70 ppd_choice_t *choice; /* Current choice */
71 ppd_coption_t *coption; /* Current custom option */
72 ppd_cparam_t *cparam; /* Current custom parameter */
73 ppd_attr_t *attr, /* Current attribute */
74 *locattr; /* Localized attribute */
75 char ckeyword[PPD_MAX_NAME], /* Custom keyword */
76 ll_CC[6], /* Language + country locale */
77 ll[3]; /* Language locale */
78
79
80 /*
81 * Range check input...
82 */
83
84 DEBUG_printf(("ppdLocalize(ppd=%p)\n", ppd));
85
86 if (!ppd)
87 return (-1);
88
89 /*
90 * Get the default language...
91 */
92
93 ppd_ll_CC(ll_CC, ll);
94
95 /*
96 * Now lookup all of the groups, options, choices, etc.
97 */
98
99 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
100 {
101 if ((locattr = ppd_localized_attr(ppd, "Translation", group->name,
102 ll_CC, ll)) != NULL)
103 strlcpy(group->text, locattr->text, sizeof(group->text));
104
105 for (j = group->num_options, option = group->options; j > 0; j --, option ++)
106 {
107 if ((locattr = ppd_localized_attr(ppd, "Translation", option->keyword,
108 ll_CC, ll)) != NULL)
109 strlcpy(option->text, locattr->text, sizeof(option->text));
110
111 for (k = option->num_choices, choice = option->choices;
112 k > 0;
113 k --, choice ++)
114 {
115 if (strcmp(choice->choice, "Custom"))
116 locattr = ppd_localized_attr(ppd, option->keyword, choice->choice,
117 ll_CC, ll);
118 else
119 {
120 snprintf(ckeyword, sizeof(ckeyword), "Custom%s", option->keyword);
121
122 locattr = ppd_localized_attr(ppd, ckeyword, "True", ll_CC, ll);
123 }
124
125 if (locattr)
126 strlcpy(choice->text, locattr->text, sizeof(choice->text));
127 }
128 }
129 }
130
131 /*
132 * Translate any custom parameters...
133 */
134
135 for (coption = (ppd_coption_t *)cupsArrayFirst(ppd->coptions);
136 coption;
137 coption = (ppd_coption_t *)cupsArrayNext(ppd->coptions))
138 {
139 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
140 cparam;
141 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
142 {
143 snprintf(ckeyword, sizeof(ckeyword), "ParamCustom%s", coption->keyword);
144
145 if ((locattr = ppd_localized_attr(ppd, ckeyword, cparam->name,
146 ll_CC, ll)) != NULL)
147 strlcpy(cparam->text, locattr->text, sizeof(cparam->text));
148 }
149 }
150
151 /*
152 * Translate ICC profile names...
153 */
154
155 if ((attr = ppdFindAttr(ppd, "APCustomColorMatchingName", NULL)) != NULL)
156 {
157 if ((locattr = ppd_localized_attr(ppd, "APCustomColorMatchingName",
158 attr->spec, ll_CC, ll)) != NULL)
159 strlcpy(attr->text, locattr->text, sizeof(attr->text));
160 }
161
162 for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
163 attr;
164 attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
165 {
166 cupsArraySave(ppd->sorted_attrs);
167
168 if ((locattr = ppd_localized_attr(ppd, "cupsICCProfile", attr->spec,
169 ll_CC, ll)) != NULL)
170 strlcpy(attr->text, locattr->text, sizeof(attr->text));
171
172 cupsArrayRestore(ppd->sorted_attrs);
173 }
174
175 /*
176 * Translate printer presets...
177 */
178
179 for (attr = ppdFindAttr(ppd, "APPrinterPreset", NULL);
180 attr;
181 attr = ppdFindNextAttr(ppd, "APPrinterPreset", NULL))
182 {
183 cupsArraySave(ppd->sorted_attrs);
184
185 if ((locattr = ppd_localized_attr(ppd, "APPrinterPreset", attr->spec,
186 ll_CC, ll)) != NULL)
187 strlcpy(attr->text, locattr->text, sizeof(attr->text));
188
189 cupsArrayRestore(ppd->sorted_attrs);
190 }
191
192 return (0);
193 }
194
195
196 /*
197 * 'ppdLocalizeIPPReason()' - Get the localized version of a cupsIPPReason
198 * attribute.
199 *
200 * This function uses the current locale to find the corresponding reason
201 * text or URI from the attribute value. If "scheme" is NULL or "text",
202 * the returned value contains human-readable (UTF-8) text from the translation
203 * string or attribute value. Otherwise the corresponding URI is returned.
204 *
205 * If no value of the requested scheme can be found, NULL is returned.
206 *
207 * @since CUPS 1.3@
208 */
209
210 const char * /* O - Value or NULL if not found */
211 ppdLocalizeIPPReason(
212 ppd_file_t *ppd, /* I - PPD file */
213 const char *reason, /* I - IPP reason keyword to look up */
214 const char *scheme, /* I - URI scheme or NULL for text */
215 char *buffer, /* I - Value buffer */
216 size_t bufsize) /* I - Size of value buffer */
217 {
218 ppd_attr_t *locattr; /* Localized attribute */
219 char ll_CC[6], /* Language + country locale */
220 ll[3], /* Language locale */
221 *bufptr, /* Pointer into buffer */
222 *bufend, /* Pointer to end of buffer */
223 *valptr; /* Pointer into value */
224 int ch, /* Hex-encoded character */
225 schemelen; /* Length of scheme name */
226
227
228 /*
229 * Range check input...
230 */
231
232 if (buffer)
233 *buffer = '\0';
234
235 if (!ppd || !reason || (scheme && !*scheme) ||
236 !buffer || bufsize < PPD_MAX_TEXT)
237 return (NULL);
238
239 /*
240 * Get the default language...
241 */
242
243 ppd_ll_CC(ll_CC, ll);
244
245 /*
246 * Find the localized attribute...
247 */
248
249 if ((locattr = ppd_localized_attr(ppd, "cupsIPPReason", reason,
250 ll_CC, ll)) == NULL)
251 locattr = ppdFindAttr(ppd, "cupsIPPReason", reason);
252
253 if (!locattr)
254 return (NULL);
255
256 /*
257 * Now find the value we need...
258 */
259
260 bufend = buffer + bufsize - 1;
261
262 if (!scheme || !strcmp(scheme, "text"))
263 {
264 /*
265 * Copy a text value (either the translation text or text:... URIs from
266 * the value...
267 */
268
269 strlcpy(buffer, locattr->text, bufsize);
270
271 for (valptr = locattr->value, bufptr = buffer; *valptr && bufptr < bufend;)
272 {
273 if (!strncmp(valptr, "text:", 5))
274 {
275 /*
276 * Decode text: URI and add to the buffer...
277 */
278
279 if (bufptr > buffer)
280 *bufptr++ = ' '; /* Add leading whitespace */
281
282 valptr += 5;
283
284 while (*valptr && !isspace(*valptr & 255) && bufptr < bufend)
285 {
286 if (*valptr == '%' && isxdigit(valptr[1] & 255) &&
287 isxdigit(valptr[2] & 255))
288 {
289 /*
290 * Pull a hex-encoded character from the URI...
291 */
292
293 valptr ++;
294
295 if (isdigit(*valptr & 255))
296 ch = (*valptr - '0') << 4;
297 else
298 ch = (tolower(*valptr) - 'a' + 10) << 4;
299 valptr ++;
300
301 if (isdigit(*valptr & 255))
302 *bufptr++ = ch | (*valptr - '0');
303 else
304 *bufptr++ = ch | (tolower(*valptr) - 'a' + 10);
305 valptr ++;
306 }
307 else if (*valptr == '+')
308 {
309 *bufptr++ = ' ';
310 valptr ++;
311 }
312 else
313 *bufptr++ = *valptr++;
314 }
315 }
316 else
317 {
318 /*
319 * Skip this URI...
320 */
321
322 while (*valptr && !isspace(*valptr & 255))
323 valptr++;
324 }
325
326 /*
327 * Skip whitespace...
328 */
329
330 while (isspace(*valptr & 255))
331 valptr ++;
332 }
333
334 if (bufptr > buffer)
335 *bufptr = '\0';
336
337 return (buffer);
338 }
339 else
340 {
341 /*
342 * Copy a URI...
343 */
344
345 schemelen = strlen(scheme);
346 if (scheme[schemelen - 1] == ':') /* Force scheme to be just the name */
347 schemelen --;
348
349 for (valptr = locattr->value, bufptr = buffer; *valptr && bufptr < bufend;)
350 {
351 if ((!strncmp(valptr, scheme, schemelen) && valptr[schemelen] == ':') ||
352 (*valptr == '/' && !strcmp(scheme, "file")))
353 {
354 /*
355 * Copy URI...
356 */
357
358 while (*valptr && !isspace(*valptr & 255) && bufptr < bufend)
359 *bufptr++ = *valptr++;
360
361 *bufptr = '\0';
362
363 return (buffer);
364 }
365 else
366 {
367 /*
368 * Skip this URI...
369 */
370
371 while (*valptr && !isspace(*valptr & 255))
372 valptr++;
373 }
374
375 /*
376 * Skip whitespace...
377 */
378
379 while (isspace(*valptr & 255))
380 valptr ++;
381 }
382
383 return (NULL);
384 }
385 }
386
387
388 /*
389 * 'ppd_ll_CC()' - Get the current locale names.
390 */
391
392 static void
393 ppd_ll_CC(char *ll_CC, /* O - Country-specific locale name */
394 char *ll) /* O - Generic locale name */
395
396 {
397 cups_lang_t *lang; /* Current language */
398
399
400 /*
401 * Get the current locale...
402 */
403
404 if ((lang = cupsLangDefault()) == NULL)
405 {
406 strcpy(ll_CC, "en_US");
407 strcpy(ll, "en");
408 return;
409 }
410
411 /*
412 * Copy the locale name...
413 */
414
415 strlcpy(ll_CC, lang->language, sizeof(ll_CC));
416 strlcpy(ll, lang->language, sizeof(ll));
417
418 if (strlen(ll_CC) == 2)
419 {
420 /*
421 * Map "ll" to primary/origin country locales to have the best
422 * chance of finding a match...
423 */
424
425 if (!strcmp(ll_CC, "cs"))
426 strcpy(ll_CC, "cs_CZ");
427 else if (!strcmp(ll_CC, "en"))
428 strcpy(ll_CC, "en_US");
429 else if (!strcmp(ll_CC, "ja"))
430 strcpy(ll_CC, "ja_JP");
431 else if (!strcmp(ll_CC, "sv"))
432 strcpy(ll_CC, "sv_SE");
433 else if (!strcmp(ll_CC, "zh"))
434 strcpy(ll_CC, "zh_CN"); /* Simplified Chinese */
435 else
436 {
437 ll_CC[2] = '_';
438 ll_CC[3] = toupper(ll_CC[0] & 255);
439 ll_CC[4] = toupper(ll_CC[1] & 255);
440 ll_CC[5] = '\0';
441 }
442 }
443
444 DEBUG_printf(("ppd_ll_CC: lang->language=\"%s\", ll=\"%s\", ll_CC=\"%s\"...\n",
445 lang->language, ll, ll_CC));
446 }
447
448
449 /*
450 * 'ppd_localized_attr()' - Find a localized attribute.
451 */
452
453 static ppd_attr_t * /* O - Localized attribute or NULL */
454 ppd_localized_attr(ppd_file_t *ppd, /* I - PPD file */
455 const char *keyword, /* I - Main keyword */
456 const char *spec, /* I - Option keyword */
457 const char *ll_CC, /* I - Language + country locale */
458 const char *ll) /* I - Language locale */
459 {
460 char lkeyword[PPD_MAX_NAME]; /* Localization keyword */
461 ppd_attr_t *attr; /* Current attribute */
462
463
464 DEBUG_printf(("ppd_text(ppd=%p, keyword=\"%s\", spec=\"%s\", "
465 "ll_CC=\"%s\", ll=\"%s\")\n",
466 ppd, keyword, spec, ll_CC, ll));
467
468 /*
469 * Look for Keyword.ll_CC, then Keyword.ll...
470 */
471
472 snprintf(lkeyword, sizeof(lkeyword), "%s.%s", ll_CC, keyword);
473 if ((attr = ppdFindAttr(ppd, lkeyword, spec)) == NULL)
474 {
475 snprintf(lkeyword, sizeof(lkeyword), "%s.%s", ll, keyword);
476 attr = ppdFindAttr(ppd, lkeyword, spec);
477
478 if (!attr && !strcmp(ll, "ja"))
479 {
480 /*
481 * Due to a bug in the CUPS DDK 1.1.0 ppdmerge program, Japanese
482 * PPD files were incorrectly assigned "jp" as the locale name
483 * instead of "ja". Support both the old (incorrect) and new
484 * locale names for Japanese...
485 */
486
487 snprintf(lkeyword, sizeof(lkeyword), "jp.%s", keyword);
488 attr = ppdFindAttr(ppd, lkeyword, spec);
489 }
490 }
491
492 #ifdef DEBUG
493 if (attr)
494 printf(" *%s %s/%s: \"%s\"\n", attr->name, attr->spec, attr->text,
495 attr->value ? attr->value : "");
496 else
497 puts(" NOT FOUND");
498 #endif /* DEBUG */
499
500 return (attr);
501 }
502
503
504 /*
505 * End of "$Id: localize.c 6686 2007-07-16 23:11:59Z mike $".
506 */