Welcome to Geeklog, Anonymous Friday, November 22 2024 @ 10:02 pm EST

Geeklog Forums

Making Geeklog Multilingual

Page navigation


Status: offline

LWC

Forum User
Full Member
Registered: 02/19/04
Posts: 818
Multilingual - as in content (Geeklog is already multilingual in structure).

Once upon a time, a smart user called Euan came up with a way to do it - but don't use this link! This code doesn't work anymore.

See, Euan's solution is not really a hack per-se. He basically replaced Geeklog's code with his own. Since Geeklog is not (and hopefully would never be) an outdated program that has no upgrades, from a programmer's view of point what he did is a major no-no!

Forget the theoretical discussion - it's already a fact that Euan's code became extinct once Geeklog was upgraded.

So what I've done was taking his code and making it version independent. I did it by hacking Geeklog's code (in the minimalist way possible) instead of replacing it.

So here it is. Unless I decide to make an official page for it, the following post is where the newest code would be and further posts would be a description of updates, so you know when to return to this post and replace the code.
 Quote

Status: offline

LWC

Forum User
Full Member
Registered: 02/19/04
Posts: 818
Check out:
  • The Checklist.
  • Notes.
    (Too bad I can't use "a name" in this site...)

  • The Checklist:


    1. [QUOTE config.php]
      $_CONF['allow_user_language'] = 1;
      [/QUOTE]
      1. Topics
        From now on, your topics' IDs must be in the shape of X_ln ("x" stands for the original topic's ID. "ln" stands for the first two letters in a certain language).
        For example, news_en, animals_he, personal_fr.
        Any topic without that extension would be ignored by Geeklog!
        In the next post, you'd see how to declare those "ln"s (for example, you could set "en" to mean english.php).

      2. Stories
        Unlike the topics, they don't have to use _ln. As a matter of fact, I suggest you only bother doing it when you have two (or more) identical stories in multiple languages. Then, if a user is inside a story and suddenly changes the language, he'd be taken to the same story in the new language (not because of Geeklog, but because of the code I shall introduce in the next post)!

      3. Polls
        Unlike stories, they have to use _ln, as they're on the same level as topics (i.e. like folders as opposed to files).
        Up to Geeklog v1.3.11, I've only hacked polls that were featured on the homepage.
        In v1.4 and above, I've hacked all polls (because it was easier to control).

      4. Register_globals / register_long_arrays
        Free! No need for those outdated things.

    2. Notes:

      1. Direct (cookie setting) links:
        The default language is set up in config.php , but if you don't certain people to get another default language?

        Well, soon you'd learn how to create a file called switchlang.php .
        You can also use it for direct links that set the cookie in advance.

        e.g. If your default contents are in English, use this when you post your link in a Hebrew site:
        [quote For example:]

        http://yourdomain.com/switchlang.php?lang=he
        [/quote]
  •  Quote

    Status: offline

    LWC

    Forum User
    Full Member
    Registered: 02/19/04
    Posts: 818
    And now, without further adieu I present to you...my hack:

    Part I - new codes:

    The following are additions of either new files or new codes to exiting files in the Geeklog system.

    1. Creating arrays of possible languages
      Or: creating a new file called languages.php (put it near config.php) :

      This file just has 2 arrays - one just for the language changer's form and one in general.
      You can enter as many languages as you want (but obviously it's useless to add languages you don't write content for anyway).

      Text Formatted Code

      <?php

      $_languages = array (
        'en' => 'English',
        'he' => 'Hebrew'
      );

      $_languagefiles = array (
        'en' => 'english_utf-8',
        'he' => 'hebrew'
      );

      ?>


       

      See the keys? That's why I've stressed before how important is it to use X_ln. That's the "ln"!

    2. Creating a "determine the language" function
      Or: a hack for system/lib-custom.php :

      First of all, let's define the most important function - this is the function I would keep using later on for everything else.
      Text Formatted Code

      function language() {
          global $_CONF, $_USER;
          if ( !empty ($_USER['language']))
              $retval = $_USER['language'];
          else if ( !empty ($_COOKIE['language']))
              $retval = $_COOKIE['language'];
          else
              $retval = $_CONF['language'];

          return $retval;
      }


       

      The default language is naturally the one from config.php

      From now on, I would usually use substr(language(), 0, 2) . Yes, that's the "ln" again!

    3. Creating a "change a language" block
      Or: a hack for system/lib-custom.php :

      Note: you will need to create a new Geeklog block and call the following function from there!

      Text Formatted Code

      function phpblock_language()
      {
          global $_CONF;
          include($_CONF['path'].'languages.php');

          $retval = '';

      if ( !isset( $_COOKIE[$_CONF['cookie_language']]))
              $need_cookies_for_lang = '<br><font size=1>(Requires cookies)</font>';

              $lang = language();

          $retval .= '<form name="change" action="'. $_CONF['site_url'] . '/switchlang.php">';
          $retval .= '<input type="hidden" name="oldlang" value="' . substr($lang, 0, 2) . '">';
          $retval .= '<select onchange="change.submit()" name="lang">';

      foreach ($_languages as $key=>$value) {
      if ($lang == $_languagefiles[$key])
      $selected = " selected";
      else $selected = "";
          $retval .= '<option value="' . $key . '"' . $selected. '>' . $value . '</option>';
      }
          $retval .= '</select>';
      if (isset($need_cookies_for_lang)) $retval .= $need_cookies_for_lang;
          $retval .= '</form>';

          return $retval;
      }


       

      Yes, this is the worst part about this hack. It demands cookies even form anonymous users. But how else can make sure a user only gets his/her language?

    4. Creating a file for the language changer's form
      Or: creating a new file called public_files/switchlang.php :
      Text Formatted Code

      <?php

      /* Reminder: always indent with 4 spaces (no tabs). */
      // +---------------------------------------------------------------------------+
      // | Geeklog 1.4                                                               |
      // +---------------------------------------------------------------------------+
      // | switchLang.php                                                            |
      // | Switches between translation files.                                       |
      // |                                                                           |
      // | Copyright (C) 2006 by the following author:   |
      // | http://lior.weissbrod.com                                      |
      // +---------------------------------------------------------------------------+
      // | Copyright (C) 2000-2003 by the following authors:                         |
      // |                                                                           |
      // | Authors: Stratos Gerakakis     - admin@stratosgear.com                    |
      // |          Robert Dobozy         - robogl7@robod.net                        |
      // +---------------------------------------------------------------------------+
      // |                                                                           |
      // | This program is free software; you can redistribute it and/or             |
      // | modify it under the terms of the GNU General Public License               |
      // | as published by the Free Software Foundation; either version 2            |
      // | of the License, or (at your option) any later version.                    |
      // |                                                                           |
      // | This program is distributed in the hope that it will be useful,           |
      // | but WITHOUT ANY WARRANTY; without even the implied warranty of            |
      // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             |
      // | GNU General Public License for more details.                              |
      // |                                                                           |
      // | You should have received a copy of the GNU General Public License         |
      // | along with this program; if not, write to the Free Software Foundation,   |
      // | Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.           |
      // |                                                                           |
      // +---------------------------------------------------------------------------+
      //

      include_once('lib-common.php');
      include($_CONF['path'].'languages.php');

      //If not allowed, just ignore and return
      if ($_CONF['allow_user_language'] == 1) {

          if (isset($_REQUEST['oldlang'])) {
              $oldlang = strtolower(COM_applyFilter($_REQUEST['oldlang']));
          }

          // do we really have a new language to switch to?
          if (isset($_REQUEST['lang'])) {
              $lang = strtolower(COM_applyFilter($_REQUEST['lang']));

          // does it exist in our current translation list?
              if( is_file( $_CONF['path_language'] . $_languagefiles[$lang] . '.php' )) {

              // Set the language cookie.
              // Mainly used for the anonymous user so the rest of his session
              // will remain in his selected language
                  setcookie ($_CONF['cookie_language'], $_languagefiles[$lang],
                             time() + 31536000, $_CONF['cookie_path'],
                             $_CONF['cookiedomain'], $_CONF['cookiesecure']);

              // if he is not anonymous, store the preference in the database
                  if ($_USER['uid'] > 1) {
                      DB_query("UPDATE {$_TABLES['users']} SET language='{$_languagefiles[$lang]}'

      WHERE uid = {$_USER['uid']}");
                  }
              }
          }
      }

      // If the user came from within your site, send them back to the referrer page
      if (isset($_SERVER['HTTP_REFERER']))
      if (strpos($_SERVER['HTTP_REFERER'], $_CONF['site_url']) !== false) {
      $ret = $_SERVER['HTTP_REFERER'];

      // Change the language's ID if needed
      if (isset($lang) && isset($oldlang)) {
      if (strpos($ret, '&') !== false) {
      $ret = split("&", $ret);
      $extra_vars = "&" . $ret[1];
      $ret = $ret[0];
      } else $extra_vars = '';

      if (substr($ret, -3) == '_' . $oldlang)
      $ret = substr_replace($ret, $lang, -2);

      $ret .= $extra_vars;
      }
      }

      // If the user didn't come from within your site, send them to your main page
      if (!isset($ret))
      $ret = $_CONF['site_url'] . '/';

      Header("Location: $ret");
      ?>


       

      The best thing I like about this is that if you change a language, you'll be taken to the same item you were in only in the new language.
      I've made many fixes and improvements in this file.

    5. Showing only stories of a certain language
      Or: a hack for public_html/index.php :

      "Empty topic" mode is an interesting case (or /index.php without any parameters - in human lingo). It pulls stories from every topic the user has access to.
      So let's add to that...in that user's language!

      Text Formatted Code

      $sql = " (date <= NOW()) AND (draft_flag = 0)";

      // custom code - start
      if (empty($topic)) {

          $lang = "%_" . substr(language(), 0, 2);

          $sql .= " AND s.tid LIKE '$lang' ";
      }
      // custom code - end

      // if a topic was provided only select those stories.
      if (!empty($topic)) {


       

      See, that's it!


    Part II - hacks to exiting codes:

    The following are (minimal as possible) modifications for existing codes. So use them instead of current codes and that means do not - I repeat, do NOT - add them in addition to the original codes as it would create a real mess and/or end life as we know it!

    1. Showing only topics of a certain language
      Or: a hack for public_html/lib-common.php -
      function COM_showTopics :

      The list of topics is the list of topics the user has access to.
      So let's add to that...in that user's language!

      Text Formatted Code

          $sql = "SELECT tid,topic,imageurl FROM {$_TABLES['topics']}";
      // custom code - start
          $lang = "%_" . substr(language(), 0, 2);
          $sql .= " WHERE tid LIKE '$lang' ";
      // custom code - end
          if( $_USER['uid'] > 1 )
          {
              $tids = DB_getItem( $_TABLES['userindex'], 'tids',
                                  "uid = '{$_USER['uid']}'" );
              if( !empty( $tids ))
              {
      // custom code - start
                  $sql .= " AND (tid NOT IN ('" . str_replace( ' ', "','", $tids )
                       . "'))" . COM_getPermSQL( 'AND' );
      // custom code - end
              }
              else
              {
      // custom code - start
                  $sql .= COM_getPermSQL( 'AND' );
      // custom code - end
              }
          }
          else
          {
      // custom code - start
                  $sql .= COM_getPermSQL( 'AND' );
      // custom code - end
          }
          if( $_CONF['sortmethod'] == 'alpha' )


       

      Those are just minimal changes. It's just that the "topics' list" code is spread across many lines.

    2. Showing only polls of a certain language
      or: a hack for public_html/lib-common.php -
      function COM_showPoll :
      Up to Geeklog v1.3.11 only! (or: before polls became a plugin).

      I've decided not to hack public_html/polls.php itself, but those of you who are still with me should know how to do it yourselves.
      However, surely I must match the homepage's polls to the chosen language, which is pretty easy.

      Text Formatted Code

          else
          {
      // custom code - start
          $lang = "%_" . substr(language(), 0, 2);
          $sql = "AND qid LIKE '$lang' ";
              $result = DB_query( "SELECT qid from {$_TABLES['pollquestions']} WHERE display = 1 $sql ORDER BY date DESC" );
      // custom code - end
              $nrows = DB_numRows( $result );


       

      Again, that's it!


    Part III - Plugins

    The following are (minimal as possible) modifications for existing codes in plugins' files. That means you must use them instead of current codes and not in addition.

    Polls (starting in Geeklog v1.4)

    1. Featured polls on the homepage
      or: a hack for /plugins/polls/functions.inc -
      function POLLS_pollVote :
      Text Formatted Code

      // custom code - start
          $lang = "%_" . substr(language(), 0, 2);
          $sql = "AND qid LIKE '$lang' ";
          $question = DB_query( "SELECT question,voters,commentcode,owner_id,group_id,perm_owner,perm_group,perm_members,perm_anon FROM {$_TABLES['pollquestions']} WHERE qid='$qid' $sql" );
      // custom code - end
          $Q = DB_fetchArray( $question );


       

    2. The polls' list page
      or: a hack for public_html/polls/index.php :
      Text Formatted Code

      // custom code - start
          $lang = "%_" . substr(language(), 0, 2);
          $sql = "qid LIKE '$lang' ";
              $query_arr = array('table' => 'pollquestions',
                                 'sql' => $sql = "SELECT *,UNIX_TIMESTAMP(date) as unixdate, display FROM {$_TABLES['pollquestions']} WHERE $sql",
      // custom code - end
                                 'query_fields' => array('question'),


       


    To the brave few who got this far - I hope your site will become multilingual soon!

    You can always contact me for help.

    And may this hack someday become official!
     Quote

    Status: offline

    samstone

    Forum User
    Full Member
    Registered: 09/29/02
    Posts: 820
    Ya, right, LWC!

    You hacked the lib-common.php and called yourself minimalist?
    Com_shwoPoll is no longer in lib-comon.php and your called yourself up-to-date?

    Just kidding! Wink

    First, it doesn't make it better. The previous code at least shows the topics in different languages. Now when I changed the language, while I am on the home page, it not only didn't find the stories, but also didn't show the topics.

    I thought maybe because your code was for 1.3.11, so I tried that on such site and it doesn't even switch language, it keep jumping back to English when I chose Hebrew.

    I think Euan's hack was more minimal than yours, except the index.php hack has problem.

    In anycase, thank for the codes. I will try to read it with my broken php-ish to figure out where the problem could be.

    Sam


     Quote

    Status: offline

    LWC

    Forum User
    Full Member
    Registered: 02/19/04
    Posts: 818
    I've added the version I use to the checklist. Do you run it?

    I'm happy to tell you I run this hack on many sites and never had a problem.

    If you read my code well enough, you'd see that unlike Euan, who used his own SQL lines, I usually just enter a new clause into existing Geeklog lines. That is why I call myself a minimalist.
    My hack for a certain code is only as big as the lines in that code.

    As for the polls, I bet you refer to the fact that it's a plugin now. Well, as much as I try to be version independent, would you mind telling me how exactly could I have prepared for that? When I'll switch versions, I'll update this topic accordingly (and write a new post that says the code was updated so people would know).

    As for the topics, make sure you went over the checklist.
     Quote

    Status: offline

    samstone

    Forum User
    Full Member
    Registered: 09/29/02
    Posts: 820
    I was just teasing you with those comments because you talked like a Leaves me speechless

    Anyway, I tested again on 1.3.11 and found out the problem was I had the user language off in my config.php. I turned it on and now it works. I am a 'minimalist' when it comes to reading Hebrews, but I see it works!

    So I attest that your super codes work! Thank you very much!

    Now, I have to figure out with the 1.4.0 because that is the multilingual site I am building on.

    I think it has to do with the changes in index.php or lib-common.php, which allow only english topics and stories to show up on the front page once the hack is in place.

    Sam
     Quote

    Status: offline

    LWC

    Forum User
    Full Member
    Registered: 02/19/04
    Posts: 818
    You're absolutely right. I've added it to the checklist. Sorry.

    As for 1.4 (polls aside), both the parts I've hacked in public_html/index.php and in function COM_showTopics in public_htm/lib-common.php were not - I repeat, not - changed! I'm telling you this after running a file comparison program! So I have no idea why you neither see in the front page only stories in your language nor topics in your language like in 1.3.11.

    Run through the checklist again.
     Quote

    Status: offline

    samstone

    Forum User
    Full Member
    Registered: 09/29/02
    Posts: 820
    LWC, Your confidence and insistance just sound obnoxious.

    But, I have nothing elses to say than a triple "Thank you!"

    The problem is here:

    Since I got used to Euan's concept, I just assigned any two letters for the language array. Since Chinese language has two types -- traditional and simplified, I couldn't use 'ch', but 'cn' and 'tw' as the common language code for 'China' and 'Taiwan'. Like in en-US and en-UK, they use zh-CN and zh-TW.

    At your insistance and confidence on your codes, I went back to use everything original on the 1.4.0. site, with your Hebrew, and to my surprised it worked. So I narrowed it down to the language files.

    So finally, after concentrating on the possible problems with language files, I found out you need the first two letters of the language file name.

    So, the following instruction:

    Topics
    From now on, your topics' IDs must be in the shape of X_ln ("x" stands for the original topic's ID. "ln" stands for the first two letters in a certain language).


    Should be:

    Topics
    From now on, your topics' IDs must be in the shape of X_ln ("x" stands for the original topic's ID. "ln" stands for the first two letters in a certain language's FILE NAME).


    The solution is changing the language file names so that they don't have the same first two letters. The reqirement is that you have to change the file names of the plugins also.
     Quote

    Status: offline

    samstone

    Forum User
    Full Member
    Registered: 09/29/02
    Posts: 820
    A question. There is a 30px gap between the dropdown menu and the bottom edge of the block. How to make it not to have such a large gap?

    Sam
     Quote

    Status: offline

    samstone

    Forum User
    Full Member
    Registered: 09/29/02
    Posts: 820
    I feel it facinating to see the left and right blocks swapped when I tested Hebrew language on 1.4.0., but didn't happen on 1.3.11.

    Is it a new feature with 1.4.0 or your sites also do the swapping with the earlier version?

    Sam
     Quote

    Status: offline

    LWC

    Forum User
    Full Member
    Registered: 02/19/04
    Posts: 818
  • samstone vs. ln
    [QUOTE samstone]
    Your confidence and insistance just sound obnoxious.
    [/QUOTE]
    And this after saying you were right and that I was sorry...

    With that said...you were totally wrong about "ln"! Think about this for a second. Did you think my code has artificial intelligence and it just reads your mind in order to match languages? Smile I wish...

    No, you declare those "ln"s in languages.php . If you wanted, you could decide there that "ch" means english.php !

  • samstone vs. blocks
    That block simply ends with a "/form" HTML tag. Anything after that is Geeklog's templates.

  • samstone vs. rtl
    Yes, my sites all do that. I've submitted a patch that does this a long time ago, but the project site is down. Here's a new topic I've just opened about this.
  •  Quote

    Status: offline

    samstone

    Forum User
    Full Member
    Registered: 09/29/02
    Posts: 820
    No, you declare those "ln"s in /languages.php . If you wanted, you could decide there that "ch" means english.php !


    No I can't declare "ch" to mean english.php. It has to be the first two letters. In my case I had to change the chinese_simplified_utf-8 and chinese_traditional_utf-8 files to simplified_chinese_utf-8 and traditional_chinese_utf-8 in order to make it work with X_tr and X_si.

    You might have to take a look at it. But, what you said makes sense, if the first two letter is the definition than why we bother to define them?

    That block simply ends with a "/form" HTML tag. Anything after that is Geeklog's templates.


    I have tried many ways with style.css because other blocks doesn't leave such a gap. I tried "display: inline" tage with all relevent left block css but doesn't work. There might be a css for "form" that I might be able to use in style.css. I have to read about it.

    Another question. Euan has a staticpage listing block that the list changes according to language. Which functions in conjunction with the hack. I can see its usefullness. Have you look at it?

    Sam
     Quote

    Status: offline

    LWC

    Forum User
    Full Member
    Registered: 02/19/04
    Posts: 818
    I don't know how else to convince you there's no artificial intelligence involved, so I'll just ask you how can the following go wrong?
    [QUOTE languages.php]


    $_languages = array (
    'bl' => 'English',
    'ch' => 'Hebrew'
    );

    $_languagefiles = array (
    'bl' => 'english_utf-8',
    'ch' => 'hebrew'
    );

    ?>
    [/QUOTE]
    In "bl" mode, you'd only see topics such news_bl, general_bl, etc.
    In "ch" mode, you'd only see news_ch, general_ch, etc.

    Just because it's English/Hebrew, doesn't mean I have to use en/he!
     Quote

    Status: offline

    samstone

    Forum User
    Full Member
    Registered: 09/29/02
    Posts: 820
    OK, this thing is driving me crazy. I couldn't believe I was wrong based on what I saw with my two open eyes on my bright and clear computer screen, so I went back to test it. And I have proven myself a total idiot! I should quit the web development industry! Banging your head

    Then the question remains. What did happen? If it wasn't the codes and it wasn't even the language files. If there is no artifical intelligence, then there must be some supernatural intelligence out there... finding something to blame to keep myself sane...hee, hee, hee Mr. Green

    Sam
     Quote

    Status: offline

    LWC

    Forum User
    Full Member
    Registered: 02/19/04
    Posts: 818
    You tell this story and don't mention the most important thing - does it work now or not...? praying it will work

    I assume it does work because you use a past tense.

    If it does, I can only assume that when it failed, it was because your topics' IDs didn't match with what you defined in languages.php .
     Quote

    Status: offline

    samstone

    Forum User
    Full Member
    Registered: 09/29/02
    Posts: 820
    Yes, everything works now.

    I have no answer as to why it didn't work. I am sure it wasn't the topic id's because it worked when I had a topic chosen. It just didn't work with the home page.

    One possibility could be due to the privious cache or cookies, since I used Euan's hack before I switched to yours.

    Sam
     Quote

    Status: offline

    LWC

    Forum User
    Full Member
    Registered: 02/19/04
    Posts: 818
    Well, now that you've confirmed it's really version independent (at least unless Geeklog really makes a drastic changes in the way it uses MySQL), I've removed the version demand in the checklist.

    So with that out of the way, it's time to hack the new polls' plugin that was introduced in Geeklog v1.4.

    I'm glad to announce I've hacked it (I've updated the original post)!

    I just need someone with Geeklog v1.4 to try it out! Report here if it works, please.
     Quote

    Status: offline

    samstone

    Forum User
    Full Member
    Registered: 09/29/02
    Posts: 820
    Got this error


    Sat Dec 31 23:34:01 2005 - 1064: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'AND qid LIKE '%_en' ORDER BY unixdate desc' at line 1. SQL in question: SELECT *,UNIX_TIMESTAMP(date) as unixdate, display FROM gl_pollquestions WHERE AND qid LIKE '%_en' ORDER BY unixdate desc ;



    Sam
     Quote

    Status: offline

    LWC

    Forum User
    Full Member
    Registered: 02/19/04
    Posts: 818
    You should use a quote box for unwrapped paragraphs like these (not to mention that it's a quote and not a code anyway). I've had to copy it to Notepad just to read it.

    Anyway, thanks. It simply had an extra "AND" in there. I've updated it. Try again.
     Quote

    Status: offline

    samstone

    Forum User
    Full Member
    Registered: 09/29/02
    Posts: 820
    Works! Big Celebration

    Just a comment. Some of your custom codes are replacements of the existing codes, in lib-common.php, poll/index.php, etc.

    Someone unaware of it would "insert" those codes and found it not working. Since the first few items were insertions, I continued to insert the rest of items. Only when it didn't work I found out that some of the lines to be repeated by your codes with a few changes. I had to comment out the old lines to make it work.

    Just a thought for making the instruction a little more user friendly.

    Thanks for the great work, and Happy New Year!

    Sam


     Quote

    Page navigation

    All times are EST. The time is now 10:02 pm.

    • Normal Topic
    • Sticky Topic
    • Locked Topic
    • New Post
    • Sticky Topic W/ New Post
    • Locked Topic W/ New Post
    •  View Anonymous Posts
    •  Able to post
    •  Filtered HTML Allowed
    •  Censored Content