├── LICENSE ├── MY_Config.php ├── MY_Lang.php ├── README.ar.md └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Walid Aqleh 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /MY_Config.php: -------------------------------------------------------------------------------- 1 | 10 | * @version 1.1.2 11 | * @based on Internationalization (i18n) library for CodeIgniter 2 by Jerome Jaglale (http://jeromejaglale.com/doc/php/codeigniter_i18n) 12 | * @link https://github.com/waqleh/CodeIgniter-Language-In-URL-Internationalization- 13 | */ 14 | 15 | class MY_Config extends CI_Config { 16 | 17 | function site_url($uri = '', $protocol = NULL) { 18 | if (is_array($uri)) { 19 | $uri = implode('/', $uri); 20 | } 21 | 22 | if (class_exists('CI_Controller')) { 23 | $CI = & get_instance(); 24 | $uri = $CI->lang->localized($uri); 25 | } 26 | 27 | return parent::site_url($uri); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /MY_Lang.php: -------------------------------------------------------------------------------- 1 | 9 | * @version 1.1.2 10 | * @based on Internationalization (i18n) library for CodeIgniter 2 by Jerome Jaglale (http://jeromejaglale.com/doc/php/codeigniter_i18n) 11 | * @link https://github.com/waqleh/CodeIgniter-Language-In-URL-Internationalization- 12 | */ 13 | class MY_Lang extends CI_Lang { 14 | /** 15 | * configuration (you can move these into a config file or get it from a database) 16 | */ 17 | 18 | /** 19 | * languages 20 | * default language is the first element 21 | * 22 | * @var array 23 | */ 24 | public $languages = [ 25 | 'en' => 'english', 26 | 'ar' => 'arabic' 27 | ]; 28 | 29 | /** 30 | * special URIs (not localized) 31 | * 32 | * @var array 33 | */ 34 | public $special = [ 35 | "" 36 | ]; 37 | 38 | /** 39 | * where to redirect if no language in URI 40 | * 41 | * @var string 42 | */ 43 | public $default_uri = ''; 44 | 45 | /** 46 | * default lang file that will be created if it doesn't exist 47 | * and will be used to automatically add any missing strings 48 | */ 49 | public $default_lang_file = 'generated_lang.php'; 50 | 51 | // -------------------------------------------------------------------- 52 | 53 | /** 54 | * Class constructor 55 | * 56 | * If URI without language then Add language current URI and redirect 57 | * If URI is special don't add language to URI 58 | * 59 | * @return void 60 | */ 61 | function __construct() { 62 | parent::__construct(); 63 | 64 | global $CFG; 65 | global $URI; 66 | 67 | if($CFG->item('default_lang_file')){ 68 | $this->default_lang_file = $CFG->item('default_lang_file'); 69 | } 70 | 71 | $segment = $URI->segment(1); 72 | 73 | if (!strlen($this->default_uri)) { 74 | $this->default_uri = $URI->uri_string(); 75 | } 76 | 77 | if (isset($this->languages[$segment])) { // URI with language -> ok 78 | $language = $this->languages[$segment]; 79 | $CFG->set_item('language', $language); 80 | } else if ($this->is_special($segment)) { // special URI -> no redirect 81 | return; 82 | } else { // URI without language -> redirect to default_uri 83 | // set default language 84 | $CFG->set_item('language', $this->languages[$this->default_lang()]); 85 | 86 | // redirect 87 | header("Location: " . $CFG->site_url($this->localized($this->default_uri)), TRUE, 301); 88 | exit; 89 | } 90 | } 91 | 92 | /** 93 | * Returns the current language 94 | * 95 | * @return string ex: return 'en' if language in CI config is 'english' 96 | */ 97 | function lang() { 98 | global $CFG; 99 | $language = $CFG->item('language'); 100 | 101 | $lang = array_search($language, $this->languages); 102 | if ($lang) { 103 | return $lang; 104 | } 105 | 106 | return NULL; // this should not happen 107 | } 108 | 109 | /** 110 | * Check if URI is special URIs (not localized) 111 | * 112 | * @param string $uri URI 113 | * @return boolean TRUE if special Or FALSE if not 114 | */ 115 | function is_special($uri) { 116 | $exploded = explode('/', $uri); 117 | if (in_array($exploded[0], $this->special)) { 118 | return TRUE; 119 | } 120 | if (isset($this->languages[$uri])) { 121 | return TRUE; 122 | } 123 | return FALSE; 124 | } 125 | 126 | /** 127 | * Switch to another language 128 | * 129 | * @param string $lang Language key 130 | * @return string URI 131 | */ 132 | function switch_uri($lang) { 133 | $CI = & get_instance(); 134 | 135 | $uri = $CI->uri->uri_string(); 136 | $exploded = explode('/', $uri); 137 | if ($exploded[0] == $this->lang() || !strlen($exploded[0])) { 138 | $exploded[0] = $lang; 139 | } 140 | $uri = implode('/', $exploded); 141 | return $uri; 142 | } 143 | 144 | /** 145 | * Check if there is a language segment in this $uri? 146 | * 147 | * @param string $uri URI 148 | * @return boolean TRUE on success or FALSE on failure 149 | */ 150 | function has_language($uri) { 151 | $first_segment = NULL; 152 | 153 | $exploded = explode('/', $uri); 154 | if (isset($exploded[0])) { 155 | if ($exploded[0] != '') { 156 | $first_segment = $exploded[0]; 157 | } else if (isset($exploded[1]) && $exploded[1] != '') { 158 | $first_segment = $exploded[1]; 159 | } 160 | } 161 | 162 | if ($first_segment != NULL) { 163 | return isset($this->languages[$first_segment]); 164 | } 165 | 166 | return FALSE; 167 | } 168 | 169 | /** 170 | * return default language: first element of $this->languages 171 | * 172 | * @return string Key of first element in $this->languages 173 | */ 174 | function default_lang() { 175 | foreach ($this->languages as $lang => $language) { 176 | return $lang; 177 | } 178 | } 179 | 180 | /** 181 | * add language segment to $uri (if appropriate) 182 | * 183 | * @param string $uri URI 184 | * @return string URI 185 | */ 186 | function localized($uri) { 187 | if ($this->has_language($uri) || $this->is_special($uri) || preg_match('/(.+)\.[a-zA-Z0-9]{2,4}$/', $uri)) { 188 | // we don't need a language segment because: 189 | // - there's already one or 190 | // - it's a special uri (set in $special) or 191 | // - that's a link to a file 192 | } else { 193 | $uri = $this->lang() . (0 !== strpos($uri, '/') ? '/' : '') . $uri; 194 | } 195 | 196 | return $uri; 197 | } 198 | 199 | /** 200 | * return translation of line (key). If line is not available add it to a general language file 201 | * 202 | * @param string $line URI 203 | * @param boolean $log_errors Optional parameters to stop logging not found lines ### UNUSED ### 204 | * @return string 205 | */ 206 | function line($line = '', $log_errors = TRUE) { 207 | $value = ($line == '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line]; 208 | if ($value === FALSE) { 209 | $file = APPPATH . 'language' . DIRECTORY_SEPARATOR . $this->languages[$this->lang()] . DIRECTORY_SEPARATOR . $this->default_lang_file; 210 | if (($found = file_exists($file)) === FALSE) { 211 | $this->create_lang_file($file); 212 | } 213 | $this->add_to_lang_file($file, $line); 214 | return $line; 215 | } 216 | return $value; 217 | } 218 | 219 | /** 220 | * create a language file 221 | * 222 | * @param string $file path of language file 223 | */ 224 | function create_lang_file($file) { 225 | try { 226 | file_put_contents($file, "load($value, $idiom, $return, $add_suffix, $alt_path); 275 | } 276 | 277 | return; 278 | } 279 | 280 | $langfile = str_replace('.php', '', $langfile); 281 | 282 | if ($add_suffix === TRUE) { 283 | $langfile = preg_replace('/_lang$/', '', $langfile) . '_lang'; 284 | } 285 | 286 | $langfile .= '.php'; 287 | 288 | if (empty($idiom) OR ! preg_match('/^[a-z_-]+$/i', $idiom)) { 289 | $config = & get_config(); 290 | $idiom = empty($config['language']) ? 'english' : $config['language']; 291 | } 292 | 293 | if ($return === FALSE && isset($this->is_loaded[$langfile]) && $this->is_loaded[$langfile] === $idiom) { 294 | return; 295 | } 296 | 297 | // Load the base file, so any others found can override it 298 | $basepath = BASEPATH . 'language' . DIRECTORY_SEPARATOR . $idiom . DIRECTORY_SEPARATOR . $langfile; 299 | if (($found = file_exists($basepath)) === TRUE) { 300 | include($basepath); 301 | } 302 | 303 | // Do we have an alternative path to look in? 304 | if ($alt_path !== '') { 305 | $alt_path .= 'language' . DIRECTORY_SEPARATOR . $idiom . DIRECTORY_SEPARATOR . $langfile; 306 | if (file_exists($alt_path)) { 307 | include($alt_path); 308 | $found = TRUE; 309 | } 310 | } else { 311 | foreach (get_instance()->load->get_package_paths(TRUE) as $package_path) { 312 | $package_path .= 'language' . DIRECTORY_SEPARATOR . $idiom . DIRECTORY_SEPARATOR . $langfile; 313 | if ($basepath !== $package_path && file_exists($package_path)) { 314 | include($package_path); 315 | $found = TRUE; 316 | break; 317 | } 318 | } 319 | } 320 | if ($found !== TRUE) { 321 | log_message('error', 'Unable to load the requested language file: language' . DIRECTORY_SEPARATOR . $idiom . DIRECTORY_SEPARATOR . $langfile); 322 | $file = APPPATH . 'language' . DIRECTORY_SEPARATOR . $this->languages[$this->lang()] . DIRECTORY_SEPARATOR . $this->default_lang_file; 323 | $this->create_lang_file($file); 324 | echo $file; 325 | require($file); 326 | } 327 | 328 | if (!isset($lang) OR ! is_array($lang)) { 329 | log_message('error', 'Language file contains no data: language' . DIRECTORY_SEPARATOR . $idiom . DIRECTORY_SEPARATOR . $langfile); 330 | 331 | if ($return === TRUE) { 332 | return array(); 333 | } 334 | return; 335 | } 336 | 337 | if ($return === TRUE) { 338 | return $lang; 339 | } 340 | 341 | $this->is_loaded[$langfile] = $idiom; 342 | $this->language = array_merge($this->language, $lang); 343 | 344 | log_message('info', 'Language file loaded: language' . DIRECTORY_SEPARATOR . $idiom . DIRECTORY_SEPARATOR . $langfile); 345 | return TRUE; 346 | } 347 | 348 | /** 349 | * return languages array 350 | * 351 | * @return array 352 | */ 353 | public function get_lang() { 354 | return $this->languages; 355 | } 356 | 357 | } 358 | -------------------------------------------------------------------------------- /README.ar.md: -------------------------------------------------------------------------------- 1 | * اقرأ هذا في لغات أخرى: 2 | [English](README.md), [عربى](README.ar.md) . * 3 | 4 | # ماذا يفعل 5 | 6 | اللغة في الرابط: 7 | 8 | - jorider.com/en/about 9 | - jorider.com/ar/about 10 | 11 | استمر في استخدام كوداجنيتر 12 | [Language Class](https://codeigniter.com/user_guide/libraries/language.html) 13 | 14 | # مثال 15 | 16 | عرض 17 | 18 |
19 | ملف اللغة الإنجليزية 20 | 21 | $lang['I\'m a man'] = "I'm a man"; 22 | ملف اللغة العربية 23 | 24 | $lang['I\'m a man'] = "انا رجل"; 25 | النتيجة مع 26 | jorider.com/en/about 27 | 28 |I'm a man
29 | النتيجة مع 30 | jorider.com/ar/about 31 | 32 |انا رجل
33 | 34 | # موضوعات مهمة 35 | 36 | لن تكون قادرا على معرفة كيفية استخدام هذه المكتبة دون معرفة كيف يعمل 37 | 38 | Language Class 39 | 40 | 41 | كوداجنيتر 42 | 43 | https://codeigniter.com/user_guide/libraries/language.html#language-class 44 | 45 | # التركيب 46 | 47 | - (clone) استنساخ المستودع 48 | - ضع 49 | `MY_Lang.php` 50 | و 51 | `MY_Config.php` 52 | في 53 | application/core 54 | 55 | # أعدادات 56 | في 57 | application/config/routes.php 58 | أضف 59 | 60 | // example: '/en/about' -> use controller 'about' 61 | $route['^en/(.+)$'] = "$1"; 62 | $route['^ar/(.+)$'] = "$1"; 63 | // '/en' and '/ar' -> use default controller 64 | $route['^(en|ar)$'] = $route['default_controller']; 65 | 66 | أمثلة أخرى: 67 | 68 | $route['^(en|ar)/contact'] = "pages/contact"; 69 | $route['^(en|ar)/privacy-policy$'] = "pages/index/privacy_policy"; 70 | $route['^(en|ar)/terms-of-use$'] = "pages/index/terms_of_use"; 71 | 72 | ملاحظة مهمة: تأكد من إضافة أمثلة أخرى قبل المسارات أعلاه: 73 | 74 | $route['^(en|ar)/contact'] = "pages/contact"; 75 | $route['^(en|ar)/privacy-policy$'] = "pages/index/privacy_policy"; 76 | $route['^(en|ar)/terms-of-use$'] = "pages/index/terms_of_use"; 77 | // example: '/en/about' -> use controller 'about' 78 | $route['^en/(.+)$'] = "$1"; 79 | $route['^ar/(.+)$'] = "$1"; 80 | // '/en' and '/ar' -> use default controller 81 | $route['^(en|ar)$'] = $route['default_controller']; 82 | 83 | # استعمال 84 | دعنا نبني صفحة ثنائية اللغة الإنجليزية / العربية. 85 | 86 | ### ملفات اللغة 87 | 88 | `application/language/english/about_lang.php` 89 | 90 | load->helper('language'); 111 | $this->load->helper('url'); 112 | 113 | // load language file 114 | $this->lang->load('about'); 115 | 116 | 117 | $this->load->view('about'); 118 | } 119 | } 120 | 121 | ### عرض 122 | 123 | `application/views/about.php` 124 | 125 | 126 | 127 | ### اختبار 128 | 129 | `http://your_base_url/en/about` 130 | 131 |I'm a man
132 | 133 | `http://your_base_url/ar/about` 134 | 135 |انا رجل
136 | 137 | # ملاحظات 138 | - قد تحتاج إلى ترجمة بعض ملفات لغة كوداجنيتر في 139 | system/language. 140 | مثال: إذا كنت تستخدم مكتبة 141 | “Form Validation” 142 | للصفحات العربية، فترجم 143 | `system/language/english/form_validation_lang.php` 144 | إلى 145 | `application/language/arabic/form_validation_lang.php`. 146 | 147 | - روابط إلى الصفحات الداخلية مسبوقة باللغة الحالية، ولكن الروابط إلى الملفات ليست كذلك. 148 | 149 | site_url('about/my_work'); 150 | // http://mywebsite.com/en/about/my_work 151 | 152 | 153 | base_url('css/styles.css'); 154 | // http://mywebsite.com/css/styles.css 155 | 156 | - الحصول على اللغة الحالية: 157 | 158 | $this->lang->lang(); 159 | // en 160 | 161 | - التبديل إلى لغة أخرى: 162 | 163 | anchor($this->lang->switch_uri('ar'),'Display current page in Arabic'); 164 | 165 | - الصفحة الجذر (/) من المفترض أن تكون نوعا من صفحة البداية، دون أي لغة محددة. يمكن تغيير ذلك: راجع "لا صفحة البداية" أدناه. 166 | 167 | - يحتوي 168 | `MY_Config.php` 169 | على تجاوز 170 | `site_url()`: 171 | إضافة شريحة لغة (عند الاقتضاء) إلى عناوين رابط التي تم إنشاؤها. يستخدم أيضا بواسطة 172 | `anchor()`, `form_open()`... 173 | 174 | - إذا لم يتم العثور على مفتاح في مجموعة اللغة سيتم إنشاء ملف يسمى 175 | `strings_lang.php` 176 | وسيتم إضافة المفتاح والقيمة إليه. مثال: 177 | 178 | 'german', 232 | 233 | `application/config/routes.php`: 234 | إضافة مسارات جديدة 235 | 236 | // مثال: الألمانية (de) 237 | $route['^de/(.+)$'] = "$1"; 238 | $route['^(en|ar|de)$'] = $route['default_controller']; 239 | 240 | - إنشاء مجلد اللغة المقابلة في 241 | application/language. 242 | لهذا المثال "الألماني"، سوف يطلق عليه 243 | German. 244 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Read this in other languages: 2 | - [English](README.md) 3 | - [عربى](README.ar.md) 4 | 5 | # What it does 6 | 7 | Language code in URL: 8 | 9 | - jorider.com/en/about 10 | - jorider.com/ar/about 11 | 12 | The [CodeIgniter Language Class][1] is used in order to fetch and display (directly in the HTML) the appropriate text defined in the respective language file. 13 | 14 | ## Examples 15 | 16 | View file 17 | 18 | 19 | English language file 20 | 21 | $lang['I\'m a man'] = "I'm a man"; 22 | Arabic language file 23 | 24 | $lang['I\'m a man'] = "انا رجل"; 25 | Result with jorider.com/en/about 26 | 27 |I'm a man
28 | Result with jorider.com/ar/about 29 | 30 |انا رجل
31 | 32 | # Usage 33 | 34 | Before using this library, please read and learn about the [CodeIgniter Language Class][1] concepts and methods. 35 | 36 | ## Installation 37 | 38 | - Clone repository; 39 | - Place the `MY_Lang.php` and `MY_Config.php` files together in the `application/core` folder. 40 | 41 | # Example of bilingual English/Arabic website: 42 | 43 | ## Configuration 44 | 45 | In _application/config/routes.php_ add: 46 | 47 | // example: '/en/about' -> use controller 'about' 48 | $route['^en/(.+)$'] = "$1"; 49 | $route['^ar/(.+)$'] = "$1"; 50 | // '/en' and '/ar' -> use default controller 51 | $route['^(en|ar)$'] = $route['default_controller']; 52 | 53 | Other routing examples: 54 | 55 | $route['^(en|ar)/contact'] = "pages/contact"; 56 | $route['^(en|ar)/privacy-policy$'] = "pages/index/privacy_policy"; 57 | $route['^(en|ar)/terms-of-use$'] = "pages/index/terms_of_use"; 58 | 59 | Important Note: make sure to add other routs before wildcards regular expression routes above: 60 | 61 | $route['^(en|ar)/contact'] = "pages/contact"; 62 | $route['^(en|ar)/privacy-policy$'] = "pages/index/privacy_policy"; 63 | $route['^(en|ar)/terms-of-use$'] = "pages/index/terms_of_use"; 64 | // example: '/en/about' -> use controller 'about' 65 | $route['^en/(.+)$'] = "$1"; 66 | $route['^ar/(.+)$'] = "$1"; 67 | // '/en' and '/ar' -> use default controller 68 | $route['^(en|ar)$'] = $route['default_controller']; 69 | 70 | ### Create _Language Files_ 71 | 72 | - `application/language/english/about_lang.php` 73 | 74 | load->helper(['language', 'url']); 95 | 96 | // load language file 97 | $this->lang->load('about'); 98 | 99 | 100 | $this->load->view('about'); 101 | } 102 | } 103 | 104 | ### Invoke directly the `lang` method in the _View_ 105 | 106 | `application/views/about.php` 107 | 108 | 109 | 110 | ## Test 111 | 112 | `http://your_base_url/en/about` 113 | 114 |I'm a man
115 | 116 | `http://your_base_url/ar/about` 117 | 118 |انا رجل
119 | 120 | ## Notes 121 | 122 | - You might need to translate some of CodeIgniter's language files in `system/language`. Example: if you're using the [Form Validation][2] library for Arabic pages, translate `system/language/english/form_validation_lang.php` to `application/language/arabic/form_validation_lang.php`. 123 | 124 | - links to internal pages are prefixed by the current language, but links to files are not. 125 | 126 | site_url('about/my_work'); 127 | // http://mywebsite.com/en/about/my_work 128 | 129 | 130 | base_url('css/styles.css'); 131 | // http://mywebsite.com/css/styles.css 132 | 133 | - Get the current language: 134 | 135 | $this->lang->lang(); 136 | // en 137 | 138 | - Switch to another language: 139 | 140 | anchor($this->lang->switch_uri('ar'),'Display current page in Arabic'); 141 | 142 | - the root page (`/`) is supposed to be some kind of splash page, without any specific language. However, this can be changed. Read the **No splash page** section below. 143 | 144 | - the CodeIgniter `system/core/Config.php` `site_url()` method is overridden in `MY_Config.php`: a language segment can be added (when appropriate) to generated URLs. It is also used by `anchor()`, `form_open()`... 145 | 146 | - If a key is not found in the language file's array, a file called `strings_lang.php` will be created and the key and value will be added to it. E.g. if `line('xyz')` is not available, `strings_lang.php` will be created and will contain: 147 | 148 | 'german', 183 | 184 | `application/config/routes.php`: add new routes 185 | 186 | // example: German (de) 187 | $route['^de/(.+)$'] = "$1"; 188 | $route['^(en|ar|de)$'] = $route['default_controller']; 189 | 190 | - create the corresponding language folder in application/language. For this _German_ example, it would be called `german`. 191 | 192 | 193 | [1]: https://codeigniter.com/user_guide/libraries/language.html 194 | [2]: https://codeigniter.com/user_guide/libraries/form_validation.html 195 | --------------------------------------------------------------------------------