10/10/2018, 09:54
Xin giải pháp về website : Multiple languages
Mong mấy bác chỉ bảo em phương cách làm website đa ngôn ngữ bằng PHP với ạ
Em dùng google thì search ra tùm lum cách nhưng ko biết cách nào là khả thi nhất ,hy vọng nhờ mấy bác đã làm qua những site này cho em biết 1 chút về kinh nghiệm thiết kế database,class và cách bố trí tổ chức file... cho những site thế này luôn
Bác nào biết những tutorial cả tiếng anh và tiếng việt(từ search google) mà mấy bác tâm đắc share cho em luôn nhé,em xin cám ơn.
Và 1 vấn đề nữa em mới viết PHP bằng OOP,thấy phiên bản PHP 5.3 hổ trợ late static binding rất hay.
Code example :
Và các lớp kế thừa
Và trong OOP có thể override các phương thức khi extends từ lớp cha,vậy chức năng các lớp và phương thức abstract có phải là thừa ko ? vì em ko biết thì khi nào thì nên dùng abstract hay interface,final ...
Mong các bác chỉ bảo thêm.
Thân
Em dùng google thì search ra tùm lum cách nhưng ko biết cách nào là khả thi nhất ,hy vọng nhờ mấy bác đã làm qua những site này cho em biết 1 chút về kinh nghiệm thiết kế database,class và cách bố trí tổ chức file... cho những site thế này luôn
Bác nào biết những tutorial cả tiếng anh và tiếng việt(từ search google) mà mấy bác tâm đắc share cho em luôn nhé,em xin cám ơn.
Và 1 vấn đề nữa em mới viết PHP bằng OOP,thấy phiên bản PHP 5.3 hổ trợ late static binding rất hay.
Code example :
Code:
Class DatabaseObject { protected static $table_name; // Common Database Methods public static function find_all() { return static::find_by_sql("SELECT * FROM ".static::$table_name); } public static function find_by_id($id=0) { $result_array =static::find_by_sql("SELECT * FROM ".static::$table_name." WHERE id={$id} LIMIT 1"); return !empty($result_array) ? array_shift($result_array) : false; } public static function find_by_sql($sql="") { global $database; $result_set = $database->query($sql); $object_array = array(); while ($row = $database->fetch_array($result_set)) { $object_array[] = static::instantiate($row); } return $object_array; } public static function count_all(){ global $database; $sql = "select count(*) from ".static::$table_name; $result_set = $database->query($sql); $row = $database->fetch_array($result_set); return array_shift($row); } private static function instantiate($record) { $class_name = get_called_class(); $object = new $class_name; // Simple, long-form approach: // $object->id = $record['id']; // $object->username = $record['username']; // $object->password = $record['password']; // $object->first_name = $record['first_name']; // $object->last_name = $record['last_name']; // More dynamic, short-form approach: foreach($record as $attribute=>$value){ if($object->has_attribute($attribute)) { $object->$attribute = $value; } } return $object; } private function has_attribute($attribute) { // We don't care about the value, we just want to know if the key exists // Will return true or false return array_key_exists($attribute, $this->attributes()); } protected function attributes() { // return an array of attribute names and their values $attributes = array(); foreach(static::$db_fields as $field) { if(property_exists($this, $field)) { $attributes[$field] = $this->$field; } } return $attributes; } protected function sanitized_attributes() { global $database; $clean_attributes = array(); // sanitize the values before submitting // Note: does not alter the actual value of each attribute foreach($this->attributes() as $key => $value){ $clean_attributes[$key] = $database->escape_value($value); } return $clean_attributes; } public function save() { // A new record won't have an id yet. return isset($this->id) ? $this->update() : $this->create(); } public function create() { global $database; // Don't forget your SQL syntax and good habits: // - INSERT INTO table (key, key) VALUES ('value', 'value') // - single-quotes around all values // - escape all values to prevent SQL injection $attributes = $this->sanitized_attributes(); $sql = "INSERT INTO ".static::$table_name." ("; $sql .= join(", ", array_keys($attributes)); $sql .= ") VALUES ('"; $sql .= join("', '", array_values($attributes)); $sql .= "')"; if($database->query($sql)) { $this->id = $database->insert_id(); return true; } else { return false; } } public function update() { global $database; // Don't forget your SQL syntax and good habits: // - UPDATE table SET key='value', key='value' WHERE condition // - single-quotes around all values // - escape all values to prevent SQL injection $attributes = $this->sanitized_attributes(); $attribute_pairs = array(); foreach($attributes as $key => $value) { $attribute_pairs[] = "{$key}='{$value}'"; } $sql = "UPDATE ".static::$table_name." SET "; $sql .= join(", ", $attribute_pairs); $sql .= " WHERE id=". $database->escape_value($this->id); $database->query($sql); return ($database->affected_rows() == 1) ? true : false; } public function delete() { global $database; // Don't forget your SQL syntax and good habits: // - DELETE FROM table WHERE condition LIMIT 1 // - escape all values to prevent SQL injection // - use LIMIT 1 $sql = "DELETE FROM ".static::$table_name; $sql .= " WHERE id=". $database->escape_value($this->id); $sql .= " LIMIT 1"; $database->query($sql); return ($database->affected_rows() == 1) ? true : false; // NB: After deleting, the instance of User still // exists, even though the database entry does not. // This can be useful, as in: // echo $user->first_name . " was deleted"; // but, for example, we can't call $user->update() // after calling $user->delete(). } }
Code:
Class User extends DatabaseObject { protected static $table_name ="users"; protected static $db_fields = array('id','username','password','first_name','last_name'); public $id; public $username; public $password; public $first_name; public $last_name; public function full_name() { if(isset($this->first_name) && isset($this->last_name)){ return $this->first_name." ".$this->last_name; } else { return ""; } } public static function authenticate($username="",$password=""){ global $database; $username= $database->escape_value($username); $password= $database->escape_value($password); $sql="SELECT * FROM users "; $sql.= "WHERE username ='{$username}' "; $sql.= "AND password ='{$password}' "; $sql.= "LIMIT 1"; $result_array= self::find_by_sql($sql); return !empty($result_array)? array_shift($result_array):false; } } -------------------------------------------------------------- class Comment extends DatabaseObject { protected static $table_name="comments"; protected static $db_fields=array('id', 'photograph_id', 'created', 'author', 'body'); public $id; public $photograph_id; public $created; public $author; public $body; // "new" is a reserved word so we use "make" (or "build") public static function make($photo_id, $author="Anonymous", $body="") { if(!empty($photo_id) && !empty($author) && !empty($body)) { $comment = new Comment(); $comment->photograph_id = (int)$photo_id; $comment->created = strftime("%Y-%m-%d %H:%M:%S", time()); $comment->author = $author; $comment->body = $body; return $comment; } else { return false; } } public static function find_comments_on($photo_id=0) { global $database; $sql = "SELECT * FROM " . self::$table_name; $sql .= " WHERE photograph_id=" .$database->escape_value($photo_id); $sql .= " ORDER BY created ASC"; return self::find_by_sql($sql); } } ------------------------------------------------------------------------ class Photograph extends DatabaseObject { protected static $table_name ="photographs"; protected static $db_fields = array('id','filename','type','size','caption'); public $id; public $filename; public $type; public $size; public $caption; private $temp_path; protected $upload_dir = "images"; public $errors = array(); protected $upload_errors = array( // http://www.php.net/manual/en/features.file-upload.errors.php UPLOAD_ERR_OK => "No errors.", UPLOAD_ERR_INI_SIZE => "Larger than upload_max_filesize.", UPLOAD_ERR_FORM_SIZE => "Larger than form MAX_FILE_SIZE.", UPLOAD_ERR_PARTIAL => "Partial upload.", UPLOAD_ERR_NO_FILE => "No file.", UPLOAD_ERR_NO_TMP_DIR => "No temporary directory.", UPLOAD_ERR_CANT_WRITE => "Can't write to disk.", UPLOAD_ERR_EXTENSION => "File upload stopped by extension." ); // Pass in $_FILE(['uploaded_file']) as an argument public function attach_file($file) { // Perform error checking on the form parameters if(!$file || empty($file) || !is_array($file)) { // error: nothing uploaded or wrong argument usage $this->errors[] = "No file was uploaded."; return false; } elseif($file['error'] != 0) { // error: report what PHP says went wrong $this->errors[] = $this->upload_errors[$file['error']]; return false; } else { // Set object attributes to the form parameters. $this->temp_path = $file['tmp_name']; $this->filename = basename($file['name']); $this->type = $file['type']; $this->size = $file['size']; // Don't worry about saving anything to the database yet. return true; } } //Override method public function save() { // A new record won't have an id yet. if(isset($this->id)) { // Really just to update the caption $this->update(); } else { // Make sure there are no errors // Can't save if there are pre-existing errors if(!empty($this->errors)) { return false; } // Make sure the caption is not too long for the DB if(strlen($this->caption) > 255) { $this->errors[] = "The caption can only be 255 characters long."; return false; } // Can't save without filename and temp location if(empty($this->filename) || empty($this->temp_path)) { $this->errors[] = "The file location was not available."; return false; } // Determine the target_path $target_path = x_public. $this->upload_dir .DS. $this->filename; // Make sure a file doesn't already exist in the target location if(file_exists($target_path)) { $this->errors[] = "The file {$this->filename} already exists."; return false; } // Attempt to move the file if(move_uploaded_file($this->temp_path, $target_path)) { // Success // Save a corresponding entry to the database if($this->create()) { // We are done with temp_path, the file isn't there anymore unset($this->temp_path); return true; } } else { // File was not moved. $this->errors[] = "The file upload failed, possibly due to incorrect permissions on the upload folder."; return false; } } } public function image_path() { return $this->upload_dir.DS.$this->filename; } public function destroy() { if($this->delete()) { $target_path = x_public. $this->image_path(); return unlink($target_path) ? true : false; }else { return false; } } public function size_as_text() { if($this->size < 1024) { return "{$this->size} bytes"; } elseif($this->size < 1048576) { $size_kb = round($this->size/1024); return "{$size_kb} KB"; } else { $size_mb = round($this->size/1048576, 1); return "{$size_mb} MB"; } } public function comments() { return Comment::find_comments_on($this->id); } }
Mong các bác chỉ bảo thêm.
Thân
Bài liên quan
file lang/en.php
+ Table tbl_title: chỉ chứa tiêu đề của news và các thứ linh tinh khác gắn với news
+ Table tbl_news: chứa nội dung của news, mỗi entry trong table ở một ngôn ngữ khác nhau. Tbl_news có thể có các field như title_id, news_id, lang_id, content, date, ...
Khi cần hiển thị news gì, ngôn ngữ nào thì chỉ cần select cái title, rồi select news ở ngôn ngữ bạn cần hiển thị tương ứng với cái title ấy.
ngôn ngữ được lưu vào session nên những trang sau tự động dùng ngôn ngữ đó. Bất cứ khi nào cần chuyển sang ngôn ngữ khác chỉ cần thêm &lang="xx" vào cuối URL là được.
1. Đa ngôn ngữ về giao diện (tĩnh)
2. Đã ngôn ngữ về nội dung (động)
cái 1 thì dễ và nhiều site đã làm. Đã là sử dụng các file language khác nhau.
Cái thứ 2 nó bao gồm cả cái 1 và đa ngôn ngữ về nội dung (song ngữ). Mỗi một trang đều có nội dung cho từng ngôn ngữ.
Riêng cái thứ 2 muốn good thì người lên kiến trúc dự án (core) phải tính trước. Khi một module nào đó được viết xong và đóng gói. Thì số nội dung theo từng ngôn ngữ cũng tương đối.
Một ví dụ:
Tôi đã xây dựng các module sau: product, news, about, contact
Trong trường hợp 1: Muốn tạo 1 site chỉ có 1 ngôn ngữ (Tiếng việt)
Trường hợp 2: muốn tạo 1 site có 2 ngôn ngữ (Việt, Anh)
Trường hợp 3: muốn tạo 1 site có 4 ngôn ngữ (Việt, Anh, Nhật)
Nếu mà thiết kế không tốt thì suốt ngày viết đi viết lại. Khi lập trình một module bất kỳ ta nên tham chiếu đến số ngôn ngữ đã được định nghĩa.
Cũng ví dụ trên. Sau khi site đã code xong hoàn toàn. Tôi chỉ cần vào phần quản lý ngôn ngữ add thêm 1 ngôn ngữ mới. Thì tất cả các module trong dự án. Phải tự refrer đến và cho nhập (quản lý), xuất (hiển thị) theo số ngôn ngữ mà thằng core quy định.
Giả sử có 1 dự án. Ban đầu chỉ có 1 ngôn ngữ nhưng sau 1 thời gian vì nhu cầu mà cần phải thêm 1,2,3... ngôn ngữ mới. LÚc này mà code lại hoặc thiết kế DB lại thì coi như điên luôn.
Nếu ng lập trình thiết kế mô hình DB tốt. Thiết việc thêm bớt ngôn ngữ chỉ là vấn đề quản trị mà rất ít liên quan đến code, DB.
Models:
Entry
Language
Như vậy khi gửi nội dung bạn phải chọn ngôn ngữ cho bài post đó. Việc còn lại là ở lớp Views, bạn sẽ xử lý để hiển thị cho đúng ngôn ngữ mà người dùng chọn lựa.
Chúc thành công !
Nếu chỉ đa ngôn ngữ về giao diện thì làm theo mình hướng dẫn.
Nếu đa ngôn ngữ về nội dung (tin tiếng anh riêng tin tiếng Việt riêng) thì thêm trường lang cho mỗi mẫu tin. Tùy theo lang nào mà truy vấn nó ra.