Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

<html> <title></title> <body> Hi!

Since the site that I develop for needs to go international, I've been happily trying to remove all English text from our Perl modules, and give them a home in html files, where they can be dealt with by a translation firm. I've run into a snag, however. Specifically, this line of code:

$month = (January,February,March,April,May,June,July,August,September,October,November,December)--$month;

Why are the month names an unquoted string? And how can I set them up for translation into other languages (e.g. french)?

Please keep in mind that I'm a web designer (I was shanghaied into development due to a lack of personnel). So please speak very slooowwly. Thank you!

Eric Mattison </body> </html>

Replies are listed 'Best First'.
(jcwren) Re: Month Names
by jcwren (Prior) on Sep 27, 2000 at 18:53 UTC
    Because unquoted strings *are* legal, when you're not using 'use strict'. And not using 'use strict' is a *very* bad idea. A better way to write that particular statement would be:
    #!/usr/local/bin/perl -w use strict; { my $mn = 3; my $month = (qw(January Feburary March April May June July August S +eptember October November December))[$mn]; print $month, "\n"; }
    But as how you should best to do your language conversion is very dependant on how you manage it in the rest of your program. Could you give an example of how you're doing it now? Are you doing global search and replaces, resource files, or a runtime variable that sets the langauge?

    --Chris

    e-mail jcwren
      { my $mn = 3; my $month = (qw(January Feburary March April May June July August S +eptember October November December))[$mn]; print $month, "\n"; }
      Be aware that at least in 5.5.3 and earlier, this list is split at runtime causing some performance penalty if invoked repeatedly. You can do the split once at compile time by wrapping a subroutine inside a BEGIN block:
      BEGIN { my @month_names = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec +); sub month_name_for { my $number = shift; die if $number < 0 or $number > $#month_names or $number != int($n +umber); $month_names[$number]; } }

      -- Randal L. Schwartz, Perl hacker

Re: Month Names
by arturo (Vicar) on Sep 27, 2000 at 19:16 UTC

    In advance of you providing answers to jcwren's questions, I have one sort of suggestion to make that I think will work for a number of setups. warning : it involves a relatively complex data structure (to fully grok it, you'll need to read up on how to use references in Perl!)

    Suppose you've got a runtime variable that selects the language, what you can do is have a hash, whose keys are the names of the various languages, and whose values are *references to* anonymous arrays, which hold the names of the months in that language.

    The syntax below is not sacrosanct, personally if I could figure out right at this moment how to use the qw(...) to get the names of the months without all the fiddly quotes, I'd be happier, but the following seems suitable for small to medium-sized projects.

    Here's a code snippet (that won't work cut n' paste! =):

    use strict; # =) my %months = ( 'English'=> ['January', 'February' ... ], 'French'=> ['Janvier', 'Fevrier', ... ], 'Italian'=> ['gennaio', 'febbraio', ...], #etc ... );
    What's nice about this setup is that since the month *numbers* are universal across the different languages (well, give or take certain Eastern Orthodox churches etc. =) you can access the name of the month quite easily :
    # $language is set at run time and would be one of 'English', # 'Italian' etc. -- the keys of your $months hash # also assumes $month_number ranges from 1 to 12; if it's 0 to 11, eli +minate the '-1' my $month_name = $month{$language}[$month_number-1];
    HTH
Re: Month Names
by ZZamboni (Curate) on Sep 28, 2000 at 01:09 UTC
    Another possibility (apart from all the other ideas here) would be to use the Date::Manip module, which can handle (both parse and produce) dates in several different languages (search in the documentation for "Language" to see the supported ones). For example:
    use strict; use Date::Manip; my $d=ParseDate("today"); foreach my $l (qw(English French Swedish German Spanish Italian)) { Date_Init("Language=$l"); print "$l: ".UnixDate($d, "%F\n"); }
    Which produces:
    English: Wednesday, September 27, 2000 French: mercredi, septembre 27, 2000 Swedish: Onsdag, September 27, 2000 German: Mittwoch, September 27, 2000 Spanish: Miercoles, Septiembre 27, 2000 Italian: Mercoledi, Settembre 27, 2000
    Note a few points:
    • I did the ParseDate before changing the language from English (the default), because otherwise I would have had to change "today" to each language in turn.
    • I couldn't find a way for it to change the format according to each language's conventions, as mentioned by ar0n.
    • If all you need are month names, Date::Manip may be overkill, because it is a very big module. But if you need dates in general, it might be worth a try.

    --ZZamboni

Re: Month Names
by Fastolfe (Vicar) on Sep 27, 2000 at 23:40 UTC
    If you're truly interested in modifying your script to support internationalization, you may be interested in Locales (see perllocale). Since all these definitions and settings are included in most advanced OS's, it makes sense to make use of them if your needs extend beyond something simple like this (otherwise that's a lot of overhead for simply getting month names out of it). Consider:
    use POSIX qw(locale_h strftime); # arturo's fix use locale; # not necessarily needed in *this* case # locale_h above and the setlocale() calls below # are only needed in normal circumstances if you # want to work outside of your machine's default # locale. for $locale (qw{ en fr de }) { setlocale(LC_TIME, $locale); for (0..11) { print "Locale $locale\n---------\n"; # strftime is now localized to $locale print strftime("%B", 0, 0, 0, 1, $_, 96); print "\n"; } }
    Note: Code samples are for conceptual use only and generally are not meant to be cut/pasted into a production application. Always 'use strict', have a thorough understanding of the code you use, and check the return values of functions and handle errors according to your needs. - Fastolfe

      Interesting ... when I do

      use POSIX qw(strftime locale_h);
      I get ":locale_h" is not exported by the POSIX module at locale.pl

      But when I do

      use POSIX qw(locale_h strftime);
      Everything's fine ..

      So, who knows what's going on? Is this some kinda weird bug, or is it documented behavior?

      Philosophy can be made out of anything -- or less

        I don't think it is documented, and it is due to trying to grandfather something in.

        POSIX.pm has an import method which is a wrapper around Exporter which is meant to allow things matching /^\w+_h$/ to have ":" appended making them tags. If you look at Exporter's documentation, tags for groups only work if the first element is a tag. So in your first example the second element is turned into a tag, and Exporter barfs on it not being exported. In your second example all works.

        For a hack to fix it, find POSIX.pm, search for "import", and add a sort of @list before it calls Exporter's import function.

(ar0n: xml to save the day once again!) Re: Month Names
by ar0n (Priest) on Sep 27, 2000 at 22:08 UTC
    As you've stated, seperating content from code is a Good Idea(tm). In the same fashion it may be wise to seperate month-names from your code.

    Personally, I like the idea of using xml for this job (because there ready-made modules for reading in your data).

    Here's an example using an xml file (which you can find here) containing month-names for various languages. Accessing the names is roughly the same way as arturo's example above:
    #!/usr/bin/perl -w use strict; use XML::Simple; my $xml = XMLin("./months.xml"); for my $lang (qw(en nl de fr)) { print $xml->{$lang}{month}[8],"\n"; }

    However, do be aware that different languages require different syntax. Dutch, for instance, has the month-day preceding the month name (e.g. "6 Februari") as opposed to "February 6". Also, in German, digits are followed with a period: "6. Februar".

    There is also some performance-loss when you're constantly accessing a disk-file.

    In any case it won't be perfect.

    Icky.

    [~]