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