Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask

Do I need an array within an array

by meetn2veg (Scribe)
on Oct 09, 2002 at 18:27 UTC ( #204005=perlquestion: print w/replies, xml ) Need Help??

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

Here's the thing - doing a milti-lingual site (wish I wasn't!!!) with a file (language.lib) that contains all common on-screen elements.

Based upon the user language ($lang) being a value from 0-3 (defining the various languages: 0-English, 1=Spanish etc...) the on-screen elements are called from the respective array contained within the language.lib file thus;

@scr_name=("Name","Nombre","Nom"); - in language.lib
$scr_name[$lang] - displays appropriate word on screen

I've come across a situation where I use numeric values for other areas but find that a single array obviously wont work.

Here's what I have in mind (and I'm sure it's possible - I just don't know how to do it yet!). OK:

$lang = (values of 0-3)
$colour = either
(0=red, 1=blue, 2=yellow) (if $lang = 0 [English])
(0=rojo, 1=azul, 2=amarillo) (if $lang = 1 #91;Spanish])

Is it possible to have something like this

so that if $lang=1 and $colour=0, rojo would be displayed on screen.

Answers on a postcard please, to....

Thanks for any help you can give, and kindest regards from Andorra,


PS: I did look throught the FAQ's and got a bit confused... :-|

Replies are listed 'Best First'.
Re: Do I need an array within an array
by Daruma (Curate) on Oct 09, 2002 at 18:54 UTC

    You are almost there!!

    Here's an array of (anonymous) arrays

    use strict; use warnings; my $lang = 0; my @name = (qw/name nombre/); my @color = ( [qw/red yellow blue/], [qw/rojo amarillo azul/], ); print "$name[$lang]\n"; print "$color[$lang][2]\n";
      Daruma - I LOVE YOU!!!

      I finally managed to suss it out! I'll buy you a beer next time you around this neck of the woods!

      Although I'm new to Perl (self-tought over 13 months) arrays and hashed etc... have really stumped me, considering what I'm trying to do - ie: a multi-lingual site not only for visitors within the pages, but also for clients within an admin area, and in between there's a system for the client (who could have the admin area set to display any of 4 languages) to see what the visitor (who could be viewing the pages in any of 4 languages) has input in a form (also up to 4 languages).

      I don't realy love you Daruma, but you should be able to see why I'm soooo chuffed. I'd also like to say a huge 'Thanks' to you all for your light-speed replies. I will be looking into the other possibilities that have also been posted.

      Nice to know there are superb people out there willing to help out the likes of up-n-coming Jedi Webmasters.


      I hope you're allowed to post 'Thank you' notes like this?!?

Re: Do I need an array within an array
by VSarkiss (Monsignor) on Oct 09, 2002 at 19:27 UTC

    You've got a good answer above if you're going to stick to arrays, but I'd prefer to use hashes, so I could use meaningful keys (rather than having to remember 0 = English, 1 = color, etc.) Something like this:

    my %display = ( english => { red => 'red', blue => 'blue', yellow => 'yellow' }, spanish => { red => 'rojo', blue => 'azul', yellow => 'amarillo' }, french => { red => 'rouge', blue => 'vert', yellow => 'jaune' # vert is green, but I forgot the word for blue ;-) } }
    This is English-centric, but of course you could use any other language for the keys. Another nice thing with this is that you can add and delete values for one language without worrying about the order in the others.

    Furthermore, once you have a language selected, you can get a reference to just one subhash and use that from there on. Like this:

    my $scr_display = $display{spanish}; print $scr_display->{red}, "\n"; # prints rojo # Now switch to a different language $scr_display = $display{french}; print $scr_display->{red}, "\n"; # prints rouge
    (Just to clarify, you can do the "language selection" thing with arrays too, it just doesn't look as nice.) Note that hashes take more space than arrays, which could be a concern if you have huge lists of words.

    You can find out more about nested data structures in Perl data structures cookbook.

      French word for the English word 'blue': bleu


        parle vou engle? :-)
        Update: 100th post! :)

        "There is no room in this country for hyphenated Americanism" ~ Theodore Roosevelt (1915)
Re: Do I need an array within an array
by thunders (Priest) on Oct 09, 2002 at 19:09 UTC
    i'd use a hash myself. but you are right in thinking a nested data structure would be a good fit here.
    %colors =( english=>[qw/red blue yellow/], spanish=>[qw/rojo azul amarillo/] ); $lang = 'spanish'; print $colors{$lang}[0];
    alternatively you could key by some color constant, then by language:
    %colors =( 'FF0000'=> { english=>'red', spanish=>'rojo' }, '0000FF'=> { english=>'blue', spanish=>'azul' } ); $color = 'FF0000'; $language = 'spanish'; print $colors{$color}{$language};
Re: Do I need an array within an array
by Enlil (Parson) on Oct 09, 2002 at 19:11 UTC
    I would try a hash.

    For example:

    my @lang_array = ["english","spanish", "portuguese"]; my %language_hash; $language_hash{english} = { "color" => "red", "language" => "English", }; $language_hash{spanish} = { "color" => "rojo", "language" => "Espanol", }; #Code to choose language from array; my $chosen_language = $lang_array[number_of_chosen_language];
    anyhow to access what you need you have only to do:

    $returned_color = $language_hash{$chosen_language}{color};

    to get back red for English or rojo for Spanish, or

    $return_language = $language_hash{$chosen_language}{language};

    to get English for English, and Espanol for Spanish. You CAN do a array of arrays, but that IMO tends to get confusing quick. The example I have just given is untested but it should work and there are less wordy ways of initializing the above hash, but that is something I would take some time to read up on, as they are pretty useful once you get the hang of them (hashes I mean).


Re: Do I need an array within an array
by l2kashe (Deacon) on Oct 09, 2002 at 19:54 UTC
    Hey there... complex data structures can be fun, quick, and compilcated/frustrating...

    In (I think) Advanced Perl Programming there was a piece about dynamic definitions of methods for OOP programming in Perl, and I thought it might be nice here.

    Basically instead of defining all the values for a given object, the creation method simply returns a number (starting at 0) and then creates arrays of values for the object, with the names being the values and the element of info for that object in the array offset returned by the creation method (Ill show below)..
    Basically they have a defined lang and then the rest of the content is output in the given lang. Therefor $lang will be constant through their instance of the application/webpage/whatever. So you can get the lang definition at the beginning, and retain that for the rest of the script, ALA..
    %base_lang = ( 'English' => '0', 'French' => '1', 'Japanese' => '2', ); # then we set up some magic arrays @red = qw(red french_word_for_red japanese_word_for_red); @hello = qw(hi bonjour japanese_word_for_hello); # now the fun $lang_num = $base_lang{$choice}; print "$red[$lang_num] is $choice for red\n"; print "$hello[$lang_num] is $choice for hello\n"; # so on and so forth

    Or even 3 arrays for each of the words in the vocab, ala
    # This is a little redundant as it recreates the @red array, # but @words has all the values so it only dissappears for # a little bit :) (@words) = @red; # Now create out arrays for all the languages in the same # order to retain our own and our data's sanity :) foreach $item (@words) { @{$item} = @words; }

    So for out example with @red (and to save space french_red and japanese_red are the other values); The above would be similar to doing
    @red = qw(red french_red japanese_red); @french_red = qw(red french_red japanese_red); @japanese_red = qw(red french_red japanese_red);

    Now you have 3 arrays, all for the color red each in the base_lang chosen, with the same values across the board (I.e English is always index 0, French index 1, etc...)
    Whats going on is you take an array index (say 0), and then use it consistently across the site/app..(It helps to think of the arrays, as standing on their end (think ladders), with the data you want in the empty space. Then you always run across the ladders sideways, and pull all the right data
    If you add another language you can simply add the lang to the base hash, and update all the arrays.

    You can even check where you need more information of a given language, by checking to make sure that it has a defined value.
    # take for granted all words are within a particular array # and we recently added German with index of 3 while ( defined($word = shift(@vocab)) ) { print "No German word for $word!\n" if (!${$word}[3]); }
    The setup may take slightly longer, and in the Advanced Perl Programming book, the author set up a sub to create a new array for a given value if you didn't already exist, but I think I have made the point clear

    Hope this helps, and feel free to ask if you have any questions

    * And the Creator, against his better judgement, wrote man.c
Another way of doing foreign language support
by jens (Pilgrim) on Oct 10, 2002 at 05:52 UTC
    Another, perhaps better way, of supporting multiple
    languages is to separate your document design from your
    content/language design.

    Here's what I mean. You can use a set of
    <language_tags> to hold your language variable text
    content, and design your web page separately.

    Next, create as many libraries as you have languages.
    Each library consists entirely of a large hash, so might look like:
    package MyWebsite::French; %translation { tag_color => 'rouge'; tag_street => 'rue'; tag_hooligan => 'anglais'; #etc }; 1;
    Finally, write a brief preparsing program that takes
    your one and only web page, sucks in each
    library in turn, and spews out the appropriate static
    web page, with your <preparsing_tags> replaced
    with the correct language.

    This makes maintenance a great deal easier, and saves
    having to do translations on the fly.

    Instead, have your CGI invoke the correct static,
    translated web page on the fly, based upon their
    browser preferences, or whatever.

    This method can also be combined with HTML::Template
    for superior results, by having preparsed, translated web pages
    each of which also possess your HTML::Template tags.


    Microsoft delendum est.
      so might look like:
      package MyWebsite::French; my %translation { tag_color => rouge; tag_street => rue; tag_hooligan => anglais; #etc 1; }
      Would you please clean up your code, this is jibberish. You have a lexical hash, which is not accessible outside of this module file; a block of which I assume it is supposed to represent an anonymous hash AKA a hash ref, your strings on the RHS of the arrows are unquoted, you separate the key/value pairs with semicolons instead of comma's, and you have a "1;" inside the hash definition instead of after it. Plus there is no "=" sign connecting the hash and the data. Well, at least your comment uses the correct delimiter. ;-)

      Cleaned up:

      package MyWebsite::French; %translation = ( tag_color => 'rouge', tag_street => 'rue', tag_hooligan => 'anglais', #etc ); 1;
      Now, one can have access to this hash via %MyWebsite::French::translation.

      Otherwise, your suggestion to use a template module sounds good to me.

Re: Do I need an array within an array
by jbeninger (Monk) on Oct 09, 2002 at 20:02 UTC
    Your question's already been answered a couple of times, it seems. I just thought I'd point out a favourite resource of mine - data structure cookbook man page. Cheers! James
Re: Do I need an array within an array
by Jaap (Curate) on Oct 09, 2002 at 18:55 UTC
    Well... a multi-dimensional array can be built by stuffing an array with references to other (anonymous) arrays.

    Searching for "complex data structures" gives you plenty of hits on this subject.

    See O'Reilly's 'Perl in a Nutshell' chapter 4 paragraph 8
Re: Do I need an array within an array
by bart (Canon) on Oct 10, 2002 at 11:46 UTC
    I wouldn't do it that way. It looks far to hard to maintain.

    I think I wouuld reverse the order of the indexes, $lang first, so you can take a reference to the whole hash of all translations for one language. I do assume that you actually want to use just one language for the output, and this way, you can drop the reference to the language itself throughout the code. Yes, I would use hashes, and string indexes, in order to get something you can read. A bit like:

    $translat{English}{red} = 'red'; $translat{English}{blue} = 'blue'; $translat{English}{yellow} = 'yellow'; $translat{Spanish}{red} = 'rojo'; $translat{Spanish}{blue} = 'azul'; $translat{Spanish}{yellow} = 'amarillo';
    (but not actually generation it this way), then, in your code, you can do:
    $t = $translat{Spanish}; print "The proper word for red is '$t->{red}'\n";
    The proper word for red is 'rojo'
    Now, as for maintaining the translations, you could use a spreadsheet-like file, perhaps as a CSV file or tab delimited text. Your people can maintain the translation data even using Excel. Part of the data can look like:


    The first row is the languages, the first column the hash keys. You might think that it's redundant with the English word, but this is a way to distinguish between synonyms, the hash key doesn't have to be the same as the English word, for example with a word "blue" having more than one meaning, you can use "colour_blue" as the hash key for the colour.

    Back to your question... You can combine strings into one hash key, for example "colour_0" for red, "colour_1" for blue, and "colour_2" for yellow, thus you can do your lookup using $t->{"colour_$colour"}. Maintainable and flexible. I like that.

    Addendum: Some Perl code to read such a tab delimited text file into a HoH as described:

    $_ = <TABLE>; chomp; (undef, my @lang) = split /\t/; while(<TABLE>) { chomp; my($key, @text) = split /\t/; for my $i (0 .. $#lang) { $translat{$lang[$i]}{$key} = $text[$i]; } }
    You can do this once, and then save the data with, for example, Storable, or Data::Dumper, so it can be loaded more quickly when in live use. Hmm... the latter can actually produce such a Perl library file as you contemplated to use.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://204005]
Approved by valdez
Front-paged by SparkeyG
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (2)
As of 2022-09-26 03:24 GMT
Find Nodes?
    Voting Booth?
    I prefer my indexes to start at:

    Results (116 votes). Check out past polls.