]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/localize.c
Merge changes from CUPS 1.5svn-r9641
[thirdparty/cups.git] / cups / localize.c
CommitLineData
fa73b229 1/*
75bd9771 2 * "$Id: localize.c 7679 2008-06-19 23:37:45Z mike $"
fa73b229 3 *
71e16022 4 * PPD localization routines for CUPS.
fa73b229 5 *
5a6b583a 6 * Copyright 2007-2010 by Apple Inc.
7594b224 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
fa73b229 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 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/".
fa73b229 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 *
5a738aea 28 * ppdLocalize() - Localize the PPD file to the current locale.
75bd9771 29 * ppdLocalizeAttr() - Localize an attribute.
5a738aea
MS
30 * ppdLocalizeIPPReason() - Get the localized version of a cupsIPPReason
31 * attribute.
32 * ppdLocalizeMarkerName() - Get the localized version of a marker-names
33 * attribute value.
a603edef
MS
34 * _ppdFreeLanguages() - Free an array of languages from _ppdGetLanguages.
35 * _ppdGetLanguages() - Get an array of languages from a PPD file.
36 * _ppdHashName() - Generate a hash value for a device or profile
37 * name.
38 * _ppdLocalizedAttr() - Find a localized attribute.
5a738aea 39 * ppd_ll_CC() - Get the current locale names.
fa73b229 40 */
41
42/*
43 * Include necessary headers.
44 */
45
71e16022 46#include "cups-private.h"
a603edef 47#include "ppd-private.h"
fa73b229 48
49
50/*
51 * Local functions...
52 */
53
f11a948a 54static cups_lang_t *ppd_ll_CC(char *ll_CC, int ll_CC_size);
fa73b229 55
56
57/*
58 * 'ppdLocalize()' - Localize the PPD file to the current locale.
89d46774 59 *
bc44d920 60 * All groups, options, and choices are localized, as are ICC profile
61 * descriptions, printer presets, and custom option parameters. Each
62 * localized string uses the UTF-8 character encoding.
63 *
426c6a59 64 * @since CUPS 1.2/Mac OS X 10.5@
fa73b229 65 */
66
67int /* O - 0 on success, -1 on error */
68ppdLocalize(ppd_file_t *ppd) /* I - PPD file */
69{
70 int i, j, k; /* Looping vars */
71 ppd_group_t *group; /* Current group */
72 ppd_option_t *option; /* Current option */
73 ppd_choice_t *choice; /* Current choice */
74 ppd_coption_t *coption; /* Current custom option */
75 ppd_cparam_t *cparam; /* Current custom parameter */
bc44d920 76 ppd_attr_t *attr, /* Current attribute */
77 *locattr; /* Localized attribute */
fa73b229 78 char ckeyword[PPD_MAX_NAME], /* Custom keyword */
a603edef 79 ll_CC[6]; /* Language + country locale */
fa73b229 80
81
82 /*
83 * Range check input...
84 */
85
e07d4801 86 DEBUG_printf(("ppdLocalize(ppd=%p)", ppd));
d09495fa 87
fa73b229 88 if (!ppd)
89 return (-1);
90
91 /*
92 * Get the default language...
93 */
94
a603edef 95 ppd_ll_CC(ll_CC, sizeof(ll_CC));
d09495fa 96
fa73b229 97 /*
98 * Now lookup all of the groups, options, choices, etc.
99 */
100
101 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
102 {
a603edef
MS
103 if ((locattr = _ppdLocalizedAttr(ppd, "Translation", group->name,
104 ll_CC)) != NULL)
bc44d920 105 strlcpy(group->text, locattr->text, sizeof(group->text));
fa73b229 106
107 for (j = group->num_options, option = group->options; j > 0; j --, option ++)
108 {
a603edef
MS
109 if ((locattr = _ppdLocalizedAttr(ppd, "Translation", option->keyword,
110 ll_CC)) != NULL)
bc44d920 111 strlcpy(option->text, locattr->text, sizeof(option->text));
fa73b229 112
113 for (k = option->num_choices, choice = option->choices;
114 k > 0;
115 k --, choice ++)
116 {
b9faaae1
MS
117 if (strcmp(choice->choice, "Custom") ||
118 !ppdFindCustomOption(ppd, option->keyword))
a603edef
MS
119 locattr = _ppdLocalizedAttr(ppd, option->keyword, choice->choice,
120 ll_CC);
fa73b229 121 else
122 {
123 snprintf(ckeyword, sizeof(ckeyword), "Custom%s", option->keyword);
124
a603edef 125 locattr = _ppdLocalizedAttr(ppd, ckeyword, "True", ll_CC);
fa73b229 126 }
127
bc44d920 128 if (locattr)
129 strlcpy(choice->text, locattr->text, sizeof(choice->text));
fa73b229 130 }
131 }
132 }
133
134 /*
135 * Translate any custom parameters...
136 */
137
138 for (coption = (ppd_coption_t *)cupsArrayFirst(ppd->coptions);
139 coption;
140 coption = (ppd_coption_t *)cupsArrayNext(ppd->coptions))
141 {
142 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
143 cparam;
144 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
145 {
146 snprintf(ckeyword, sizeof(ckeyword), "ParamCustom%s", coption->keyword);
147
a603edef
MS
148 if ((locattr = _ppdLocalizedAttr(ppd, ckeyword, cparam->name,
149 ll_CC)) != NULL)
bc44d920 150 strlcpy(cparam->text, locattr->text, sizeof(cparam->text));
fa73b229 151 }
152 }
153
f42414bf 154 /*
155 * Translate ICC profile names...
156 */
157
158 if ((attr = ppdFindAttr(ppd, "APCustomColorMatchingName", NULL)) != NULL)
159 {
a603edef
MS
160 if ((locattr = _ppdLocalizedAttr(ppd, "APCustomColorMatchingName",
161 attr->spec, ll_CC)) != NULL)
bc44d920 162 strlcpy(attr->text, locattr->text, sizeof(attr->text));
f42414bf 163 }
164
165 for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
166 attr;
167 attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
168 {
169 cupsArraySave(ppd->sorted_attrs);
170
a603edef
MS
171 if ((locattr = _ppdLocalizedAttr(ppd, "cupsICCProfile", attr->spec,
172 ll_CC)) != NULL)
bc44d920 173 strlcpy(attr->text, locattr->text, sizeof(attr->text));
f42414bf 174
175 cupsArrayRestore(ppd->sorted_attrs);
176 }
177
09a101d6 178 /*
179 * Translate printer presets...
180 */
181
182 for (attr = ppdFindAttr(ppd, "APPrinterPreset", NULL);
183 attr;
184 attr = ppdFindNextAttr(ppd, "APPrinterPreset", NULL))
185 {
186 cupsArraySave(ppd->sorted_attrs);
187
a603edef
MS
188 if ((locattr = _ppdLocalizedAttr(ppd, "APPrinterPreset", attr->spec,
189 ll_CC)) != NULL)
bc44d920 190 strlcpy(attr->text, locattr->text, sizeof(attr->text));
09a101d6 191
192 cupsArrayRestore(ppd->sorted_attrs);
193 }
194
fa73b229 195 return (0);
196}
197
198
75bd9771
MS
199/*
200 * 'ppdLocalizeAttr()' - Localize an attribute.
201 *
202 * This function uses the current locale to find the localized attribute for
203 * the given main and option keywords. If no localized version of the
204 * attribute exists for the current locale, the unlocalized version is returned.
205 */
206
207ppd_attr_t * /* O - Localized attribute or @code NULL@ if none exists */
208ppdLocalizeAttr(ppd_file_t *ppd, /* I - PPD file */
209 const char *keyword, /* I - Main keyword */
210 const char *spec) /* I - Option keyword or @code NULL@ for none */
211{
212 ppd_attr_t *locattr; /* Localized attribute */
213 char ll_CC[6]; /* Language + country locale */
214
215
216 /*
217 * Get the default language...
218 */
219
220 ppd_ll_CC(ll_CC, sizeof(ll_CC));
221
222 /*
223 * Find the localized attribute...
224 */
225
226 if (spec)
227 locattr = _ppdLocalizedAttr(ppd, keyword, spec, ll_CC);
228 else
229 locattr = _ppdLocalizedAttr(ppd, "Translation", keyword, ll_CC);
230
231 if (!locattr)
232 locattr = ppdFindAttr(ppd, keyword, spec);
233
234 return (locattr);
235}
236
237
fa73b229 238/*
bc44d920 239 * 'ppdLocalizeIPPReason()' - Get the localized version of a cupsIPPReason
240 * attribute.
241 *
242 * This function uses the current locale to find the corresponding reason
243 * text or URI from the attribute value. If "scheme" is NULL or "text",
244 * the returned value contains human-readable (UTF-8) text from the translation
245 * string or attribute value. Otherwise the corresponding URI is returned.
246 *
247 * If no value of the requested scheme can be found, NULL is returned.
248 *
426c6a59 249 * @since CUPS 1.3/Mac OS X 10.5@
bc44d920 250 */
251
252const char * /* O - Value or NULL if not found */
253ppdLocalizeIPPReason(
254 ppd_file_t *ppd, /* I - PPD file */
255 const char *reason, /* I - IPP reason keyword to look up */
256 const char *scheme, /* I - URI scheme or NULL for text */
257 char *buffer, /* I - Value buffer */
258 size_t bufsize) /* I - Size of value buffer */
259{
f11a948a 260 cups_lang_t *lang; /* Current language */
bc44d920 261 ppd_attr_t *locattr; /* Localized attribute */
262 char ll_CC[6], /* Language + country locale */
bc44d920 263 *bufptr, /* Pointer into buffer */
264 *bufend, /* Pointer to end of buffer */
265 *valptr; /* Pointer into value */
266 int ch, /* Hex-encoded character */
267 schemelen; /* Length of scheme name */
268
269
270 /*
271 * Range check input...
272 */
273
274 if (buffer)
275 *buffer = '\0';
276
277 if (!ppd || !reason || (scheme && !*scheme) ||
278 !buffer || bufsize < PPD_MAX_TEXT)
279 return (NULL);
280
281 /*
282 * Get the default language...
283 */
284
f11a948a 285 lang = ppd_ll_CC(ll_CC, sizeof(ll_CC));
bc44d920 286
287 /*
288 * Find the localized attribute...
289 */
290
a603edef
MS
291 if ((locattr = _ppdLocalizedAttr(ppd, "cupsIPPReason", reason,
292 ll_CC)) == NULL)
bc44d920 293 locattr = ppdFindAttr(ppd, "cupsIPPReason", reason);
294
295 if (!locattr)
f11a948a
MS
296 {
297 if (lang && (!scheme || !strcmp(scheme, "text")))
298 {
299 /*
300 * Try to localize a standard printer-state-reason keyword...
301 */
302
303 const char *message = NULL; /* Localized message */
304
f11a948a 305 if (!strncmp(reason, "media-needed", 12))
5a6b583a 306 message = _("The paper tray needs to be filled.");
f11a948a 307 else if (!strncmp(reason, "media-jam", 9))
5a6b583a 308 message = _("There is a paper jam.");
178cb736 309 else if (!strncmp(reason, "offline", 7) ||
5a6b583a 310 !strncmp(reason, "shutdown", 8))
84315f46 311 message = _("The printer is not connected.");
f11a948a 312 else if (!strncmp(reason, "toner-low", 9))
5a6b583a 313 message = _("The printer is low on toner.");
f11a948a 314 else if (!strncmp(reason, "toner-empty", 11))
5a6b583a 315 message = _("The printer is out of toner.");
f11a948a 316 else if (!strncmp(reason, "cover-open", 10))
5a6b583a 317 message = _("The printer's cover is open.");
f11a948a 318 else if (!strncmp(reason, "interlock-open", 14))
5a6b583a 319 message = _("The printer's interlock is open.");
f11a948a 320 else if (!strncmp(reason, "door-open", 9))
5a6b583a 321 message = _("The printer's door is open.");
f11a948a 322 else if (!strncmp(reason, "input-tray-missing", 18))
5a6b583a 323 message = _("The paper tray is missing.");
f11a948a 324 else if (!strncmp(reason, "media-low", 9))
5a6b583a 325 message = _("The paper tray is almost empty.");
f11a948a 326 else if (!strncmp(reason, "media-empty", 11))
5a6b583a 327 message = _("The paper tray is empty.");
f11a948a 328 else if (!strncmp(reason, "output-tray-missing", 19))
5a6b583a 329 message = _("The output bin is missing.");
f11a948a 330 else if (!strncmp(reason, "output-area-almost-full", 23))
5a6b583a 331 message = _("The output bin is almost full.");
f11a948a 332 else if (!strncmp(reason, "output-area-full", 16))
5a6b583a 333 message = _("The output bin is full.");
f11a948a 334 else if (!strncmp(reason, "marker-supply-low", 17))
5a6b583a 335 message = _("The printer is almost out of ink.");
f11a948a 336 else if (!strncmp(reason, "marker-supply-empty", 19))
5a6b583a 337 message = _("The printer is out of ink.");
f11a948a 338 else if (!strncmp(reason, "marker-waste-almost-full", 24))
5a6b583a 339 message = _("The printer's waste bin is almost full.");
f11a948a 340 else if (!strncmp(reason, "marker-waste-full", 17))
5a6b583a 341 message = _("The printer's waste bin is full.");
f11a948a 342 else if (!strncmp(reason, "fuser-over-temp", 15))
5a6b583a 343 message = _("The fuser's temperature is high.");
f11a948a 344 else if (!strncmp(reason, "fuser-under-temp", 16))
5a6b583a 345 message = _("The fuser's temperature is low.");
f11a948a 346 else if (!strncmp(reason, "opc-near-eol", 12))
5a6b583a 347 message = _("The optical photoconductor will need to be replaced soon.");
f11a948a 348 else if (!strncmp(reason, "opc-life-over", 13))
5a6b583a 349 message = _("The optical photoconductor needs to be replaced.");
f11a948a 350 else if (!strncmp(reason, "developer-low", 13))
5a6b583a 351 message = _("The developer unit will need to be replaced soon.");
f11a948a 352 else if (!strncmp(reason, "developer-empty", 15))
5a6b583a
MS
353 message = _("The developer unit needs to be replaced.");
354
f11a948a
MS
355 if (message)
356 {
357 strlcpy(buffer, _cupsLangString(lang, message), bufsize);
358 return (buffer);
359 }
360 }
361
bc44d920 362 return (NULL);
f11a948a 363 }
bc44d920 364
365 /*
366 * Now find the value we need...
367 */
368
369 bufend = buffer + bufsize - 1;
370
371 if (!scheme || !strcmp(scheme, "text"))
372 {
373 /*
374 * Copy a text value (either the translation text or text:... URIs from
375 * the value...
376 */
377
378 strlcpy(buffer, locattr->text, bufsize);
379
380 for (valptr = locattr->value, bufptr = buffer; *valptr && bufptr < bufend;)
381 {
382 if (!strncmp(valptr, "text:", 5))
383 {
384 /*
385 * Decode text: URI and add to the buffer...
386 */
387
bc44d920 388 valptr += 5;
389
7cf5915e 390 while (*valptr && !_cups_isspace(*valptr) && bufptr < bufend)
bc44d920 391 {
392 if (*valptr == '%' && isxdigit(valptr[1] & 255) &&
393 isxdigit(valptr[2] & 255))
394 {
395 /*
396 * Pull a hex-encoded character from the URI...
397 */
398
399 valptr ++;
400
401 if (isdigit(*valptr & 255))
402 ch = (*valptr - '0') << 4;
403 else
404 ch = (tolower(*valptr) - 'a' + 10) << 4;
405 valptr ++;
406
407 if (isdigit(*valptr & 255))
408 *bufptr++ = ch | (*valptr - '0');
409 else
410 *bufptr++ = ch | (tolower(*valptr) - 'a' + 10);
411 valptr ++;
412 }
413 else if (*valptr == '+')
414 {
415 *bufptr++ = ' ';
416 valptr ++;
417 }
418 else
419 *bufptr++ = *valptr++;
420 }
421 }
422 else
423 {
424 /*
425 * Skip this URI...
426 */
427
7cf5915e 428 while (*valptr && !_cups_isspace(*valptr))
bc44d920 429 valptr++;
430 }
431
432 /*
433 * Skip whitespace...
434 */
435
7cf5915e 436 while (_cups_isspace(*valptr))
bc44d920 437 valptr ++;
438 }
439
440 if (bufptr > buffer)
441 *bufptr = '\0';
442
443 return (buffer);
444 }
445 else
446 {
447 /*
448 * Copy a URI...
449 */
450
451 schemelen = strlen(scheme);
452 if (scheme[schemelen - 1] == ':') /* Force scheme to be just the name */
453 schemelen --;
454
455 for (valptr = locattr->value, bufptr = buffer; *valptr && bufptr < bufend;)
456 {
457 if ((!strncmp(valptr, scheme, schemelen) && valptr[schemelen] == ':') ||
458 (*valptr == '/' && !strcmp(scheme, "file")))
459 {
460 /*
461 * Copy URI...
462 */
463
7cf5915e 464 while (*valptr && !_cups_isspace(*valptr) && bufptr < bufend)
bc44d920 465 *bufptr++ = *valptr++;
466
467 *bufptr = '\0';
468
469 return (buffer);
470 }
471 else
472 {
473 /*
474 * Skip this URI...
475 */
476
7cf5915e 477 while (*valptr && !_cups_isspace(*valptr))
bc44d920 478 valptr++;
479 }
480
481 /*
482 * Skip whitespace...
483 */
484
7cf5915e 485 while (_cups_isspace(*valptr))
bc44d920 486 valptr ++;
487 }
488
489 return (NULL);
490 }
491}
492
493
5a738aea
MS
494/*
495 * 'ppdLocalizeMarkerName()' - Get the localized version of a marker-names
496 * attribute value.
497 *
498 * This function uses the current locale to find the corresponding name
499 * text from the attribute value. If no localized text for the requested
500 * name can be found, @code NULL@ is returned.
501 *
178cb736 502 * @since CUPS 1.4/Mac OS X 10.6@
5a738aea
MS
503 */
504
505const char * /* O - Value or @code NULL@ if not found */
506ppdLocalizeMarkerName(
507 ppd_file_t *ppd, /* I - PPD file */
508 const char *name) /* I - Marker name to look up */
509{
510 ppd_attr_t *locattr; /* Localized attribute */
a603edef 511 char ll_CC[6]; /* Language + country locale */
5a738aea
MS
512
513
514 /*
515 * Range check input...
516 */
517
518 if (!ppd || !name)
519 return (NULL);
520
521 /*
522 * Get the default language...
523 */
524
a603edef 525 ppd_ll_CC(ll_CC, sizeof(ll_CC));
5a738aea
MS
526
527 /*
528 * Find the localized attribute...
529 */
530
a603edef
MS
531 if ((locattr = _ppdLocalizedAttr(ppd, "cupsMarkerName", name,
532 ll_CC)) == NULL)
5a738aea
MS
533 locattr = ppdFindAttr(ppd, "cupsMarkerName", name);
534
535 return (locattr ? locattr->text : NULL);
536}
537
538
bc44d920 539/*
a603edef 540 * '_ppdFreeLanguages()' - Free an array of languages from _ppdGetLanguages.
bc44d920 541 */
542
a603edef
MS
543void
544_ppdFreeLanguages(
545 cups_array_t *languages) /* I - Languages array */
bc44d920 546{
a603edef
MS
547 char *language; /* Current language */
548
549
550 for (language = (char *)cupsArrayFirst(languages);
551 language;
552 language = (char *)cupsArrayNext(languages))
553 free(language);
554
555 cupsArrayDelete(languages);
556}
557
558
559/*
560 * '_ppdGetLanguages()' - Get an array of languages from a PPD file.
561 */
562
563cups_array_t * /* O - Languages array */
564_ppdGetLanguages(ppd_file_t *ppd) /* I - PPD file */
565{
566 cups_array_t *languages; /* Languages array */
567 ppd_attr_t *attr; /* cupsLanguages attribute */
568 char *value, /* Copy of attribute value */
569 *start, /* Start of current language */
570 *ptr; /* Pointer into languages */
bc44d920 571
572
573 /*
a603edef 574 * See if we have a cupsLanguages attribute...
bc44d920 575 */
576
a603edef
MS
577 if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) == NULL || !attr->value)
578 return (NULL);
bc44d920 579
580 /*
a603edef 581 * Yes, load the list...
bc44d920 582 */
583
a603edef
MS
584 if ((languages = cupsArrayNew((cups_array_func_t)strcmp, NULL)) == NULL)
585 return (NULL);
db1f069b 586
a603edef
MS
587 if ((value = strdup(attr->value)) == NULL)
588 {
589 cupsArrayDelete(languages);
590 return (NULL);
591 }
bc44d920 592
a603edef 593 for (ptr = value; *ptr;)
bc44d920 594 {
595 /*
a603edef 596 * Skip leading whitespace...
bc44d920 597 */
598
7cf5915e 599 while (_cups_isspace(*ptr))
a603edef
MS
600 ptr ++;
601
602 if (!*ptr)
603 break;
604
605 /*
606 * Find the end of this language name...
607 */
608
7cf5915e 609 for (start = ptr; *ptr && !_cups_isspace(*ptr); ptr ++);
a603edef
MS
610
611 if (*ptr)
612 *ptr++ = '\0';
613
614 if (!strcmp(start, "en"))
615 continue;
616
617 cupsArrayAdd(languages, strdup(start));
618 }
619
620 /*
621 * Free the temporary string and return either an array with one or more
622 * values or a NULL pointer...
623 */
624
625 free(value);
626
627 if (cupsArrayCount(languages) == 0)
628 {
629 cupsArrayDelete(languages);
630 return (NULL);
bc44d920 631 }
a603edef
MS
632 else
633 return (languages);
634}
635
636
637/*
638 * '_ppdHashName()' - Generate a hash value for a device or profile name.
639 *
640 * This function is primarily used on Mac OS X, but is generally accessible
641 * since cupstestppd needs to check for profile name collisions in PPD files...
642 */
643
644unsigned /* O - Hash value */
645_ppdHashName(const char *name) /* I - Name to hash */
646{
647 int mult; /* Multiplier */
648 unsigned hash = 0; /* Hash value */
649
bc44d920 650
a603edef
MS
651 for (mult = 1; *name && mult <= 128; mult ++, name ++)
652 hash += (*name & 255) * mult;
653
654 return (hash);
bc44d920 655}
656
657
658/*
a603edef 659 * '_ppdLocalizedAttr()' - Find a localized attribute.
fa73b229 660 */
661
a603edef
MS
662ppd_attr_t * /* O - Localized attribute or NULL */
663_ppdLocalizedAttr(ppd_file_t *ppd, /* I - PPD file */
664 const char *keyword, /* I - Main keyword */
665 const char *spec, /* I - Option keyword */
666 const char *ll_CC) /* I - Language + country locale */
fa73b229 667{
668 char lkeyword[PPD_MAX_NAME]; /* Localization keyword */
669 ppd_attr_t *attr; /* Current attribute */
670
671
e07d4801
MS
672 DEBUG_printf(("4_ppdLocalizedAttr(ppd=%p, keyword=\"%s\", spec=\"%s\", "
673 "ll_CC=\"%s\")", ppd, keyword, spec, ll_CC));
d09495fa 674
fa73b229 675 /*
676 * Look for Keyword.ll_CC, then Keyword.ll...
677 */
678
d09495fa 679 snprintf(lkeyword, sizeof(lkeyword), "%s.%s", ll_CC, keyword);
fa73b229 680 if ((attr = ppdFindAttr(ppd, lkeyword, spec)) == NULL)
681 {
c9fc04c6 682 snprintf(lkeyword, sizeof(lkeyword), "%2.2s.%s", ll_CC, keyword);
fa73b229 683 attr = ppdFindAttr(ppd, lkeyword, spec);
7594b224 684
db1f069b 685 if (!attr)
7594b224 686 {
a603edef 687 if (!strncmp(ll_CC, "ja", 2))
db1f069b
MS
688 {
689 /*
690 * Due to a bug in the CUPS DDK 1.1.0 ppdmerge program, Japanese
691 * PPD files were incorrectly assigned "jp" as the locale name
692 * instead of "ja". Support both the old (incorrect) and new
693 * locale names for Japanese...
694 */
7594b224 695
db1f069b
MS
696 snprintf(lkeyword, sizeof(lkeyword), "jp.%s", keyword);
697 attr = ppdFindAttr(ppd, lkeyword, spec);
698 }
a603edef 699 else if (!strncmp(ll_CC, "no", 2))
db1f069b
MS
700 {
701 /*
702 * Norway has two languages, "Bokmal" (the primary one)
703 * and "Nynorsk" (new Norwegian); we map "no" to "nb" here as
704 * recommended by the locale folks...
705 */
706
707 snprintf(lkeyword, sizeof(lkeyword), "nb.%s", keyword);
708 attr = ppdFindAttr(ppd, lkeyword, spec);
709 }
7594b224 710 }
fa73b229 711 }
712
d09495fa 713#ifdef DEBUG
714 if (attr)
e07d4801 715 DEBUG_printf(("5_ppdLocalizedAttr: *%s %s/%s: \"%s\"\n", attr->name,
ae71f5de 716 attr->spec, attr->text, attr->value ? attr->value : ""));
d09495fa 717 else
e07d4801 718 DEBUG_puts("5_ppdLocalizedAttr: NOT FOUND");
d09495fa 719#endif /* DEBUG */
720
bc44d920 721 return (attr);
fa73b229 722}
723
724
725/*
a603edef
MS
726 * 'ppd_ll_CC()' - Get the current locale names.
727 */
728
f11a948a 729static cups_lang_t * /* O - Current language */
a603edef
MS
730ppd_ll_CC(char *ll_CC, /* O - Country-specific locale name */
731 int ll_CC_size) /* I - Size of country-specific name */
732{
733 cups_lang_t *lang; /* Current language */
734
735
736 /*
737 * Get the current locale...
738 */
739
740 if ((lang = cupsLangDefault()) == NULL)
741 {
742 strlcpy(ll_CC, "en_US", ll_CC_size);
f11a948a 743 return (NULL);
a603edef
MS
744 }
745
746 /*
747 * Copy the locale name...
748 */
749
750 strlcpy(ll_CC, lang->language, ll_CC_size);
751
752 if (strlen(ll_CC) == 2)
753 {
754 /*
755 * Map "ll" to primary/origin country locales to have the best
756 * chance of finding a match...
757 */
758
759 if (!strcmp(ll_CC, "cs"))
760 strlcpy(ll_CC, "cs_CZ", ll_CC_size);
761 else if (!strcmp(ll_CC, "en"))
762 strlcpy(ll_CC, "en_US", ll_CC_size);
763 else if (!strcmp(ll_CC, "ja"))
764 strlcpy(ll_CC, "ja_JP", ll_CC_size);
765 else if (!strcmp(ll_CC, "sv"))
766 strlcpy(ll_CC, "sv_SE", ll_CC_size);
767 else if (!strcmp(ll_CC, "zh")) /* Simplified Chinese */
768 strlcpy(ll_CC, "zh_CN", ll_CC_size);
a603edef
MS
769 }
770
e07d4801 771 DEBUG_printf(("8ppd_ll_CC: lang->language=\"%s\", ll_CC=\"%s\"...",
a603edef 772 lang->language, ll_CC));
f11a948a 773 return (lang);
a603edef
MS
774}
775
776
777/*
75bd9771 778 * End of "$Id: localize.c 7679 2008-06-19 23:37:45Z mike $".
fa73b229 779 */