Trang web đa ngôn ngữ thực hành tốt nhất


179

Tôi đã đấu tranh với câu hỏi này trong một vài tháng nay, nhưng tôi đã không ở trong một tình huống mà tôi cần phải khám phá tất cả các lựa chọn có thể trước đây. Ngay bây giờ, tôi cảm thấy như đã đến lúc tìm hiểu các khả năng và tạo ra sở thích cá nhân của riêng mình để sử dụng trong các dự án sắp tới của mình.

Trước tiên hãy để tôi phác họa tình huống tôi đang tìm kiếm

Tôi sắp nâng cấp / phát triển lại một hệ thống quản lý nội dung mà tôi đã sử dụng khá lâu rồi. Tuy nhiên, tôi cảm thấy đa ngôn ngữ là một cải tiến tuyệt vời cho hệ thống này. Trước đây tôi không sử dụng bất kỳ khuôn khổ nào nhưng tôi sẽ sử dụng Laraval4 cho dự án sắp tới. Laravel dường như là sự lựa chọn tốt nhất về cách viết mã PHP sạch hơn. Sidenote: Laraval4 should be no factor in your answer. Tôi đang tìm kiếm những cách dịch chung chung là độc lập với nền tảng / khung.

Những gì nên được dịch

Vì hệ thống tôi đang tìm kiếm cần phải thân thiện với người dùng nhất có thể, phương pháp quản lý bản dịch phải nằm trong CMS. Không cần thiết phải khởi động kết nối FTP để sửa đổi các tệp dịch hoặc bất kỳ mẫu phân tích cú pháp html / php nào.

Hơn nữa, tôi đang tìm cách dễ nhất để dịch nhiều bảng cơ sở dữ liệu có lẽ mà không cần phải tạo thêm bảng.

Tôi đã nghĩ ra cái gì

Như tôi đã tìm kiếm, đọc và thử mọi thứ bản thân mình. Có một vài lựa chọn tôi có. Nhưng tôi vẫn không cảm thấy như mình đã đạt được một phương pháp thực hành tốt nhất cho những gì tôi thực sự đang tìm kiếm. Ngay bây giờ, đây là những gì tôi nghĩ ra, nhưng phương pháp này cũng có tác dụng phụ.

  1. Các mẫu được phân tích cú pháp PHP: hệ thống mẫu nên được phân tích cú pháp bởi PHP. Bằng cách này, tôi có thể chèn các tham số đã dịch vào HTML mà không cần phải mở các mẫu và sửa đổi chúng. Ngoài ra, các mẫu được phân tích cú pháp PHP cung cấp cho tôi khả năng có 1 mẫu cho trang web hoàn chỉnh thay vì có thư mục con cho mỗi ngôn ngữ (mà tôi đã có trước đây). Phương pháp để đạt được mục tiêu này có thể là Smarty, TemplatePower, Laravel's Blade hoặc bất kỳ trình phân tích cú pháp mẫu nào khác. Như tôi đã nói điều này nên độc lập với giải pháp bằng văn bản.
  2. Cơ sở dữ liệu hướng dẫn : có lẽ tôi không cần phải đề cập đến điều này một lần nữa. Nhưng giải pháp nên được điều khiển cơ sở dữ liệu. CMS hướng đến đối tượng và MVC, vì vậy tôi cần nghĩ về cấu trúc dữ liệu logic cho các chuỗi. Vì các mẫu của tôi sẽ được cấu trúc: samples / Controller / View.php có lẽ cấu trúc này sẽ có ý nghĩa nhất : Controller.View.parameter. Bảng cơ sở dữ liệu sẽ có các trường này dài với một valuetrường. Trong các mẫu chúng ta có thể sử dụng một số phương thức sắp xếp như echo __('Controller.View.welcome', array('name', 'Joshua'))và tham số chứa Welcome, :name. Do đó, kết quả là Welcome, Joshua. Đây có vẻ là một cách tốt để làm điều này, bởi vì các tham số như: tên rất dễ hiểu bởi trình soạn thảo.
  3. Tải cơ sở dữ liệu thấp : Tất nhiên hệ thống trên sẽ gây ra tải tải cơ sở dữ liệu nếu các chuỗi này đang được tải khi đang di chuyển. Do đó, tôi sẽ cần một hệ thống lưu trữ bộ nhớ lại kết xuất lại các tệp ngôn ngữ ngay khi chúng được chỉnh sửa / lưu trong môi trường quản trị. Bởi vì các tập tin được tạo ra, cũng cần một bố trí hệ thống tập tin tốt. Tôi đoán chúng ta có thể đi với languages/en_EN/Controller/View.phphoặc .ini, bất cứ điều gì phù hợp với bạn nhất. Có lẽ một .ini thậm chí còn được phân tích cú pháp nhanh hơn cuối cùng. Fould này nên chứa dữ liệu trong format parameter=value; . Tôi đoán đây là cách tốt nhất để làm điều này, vì mỗi Chế độ xem được hiển thị có thể bao gồm tệp ngôn ngữ của chính nó nếu nó tồn tại. Các tham số ngôn ngữ sau đó nên được tải vào một chế độ xem cụ thể chứ không phải trong phạm vi toàn cầu để ngăn các tham số ghi đè lên nhau.
  4. Bảng dịch cơ sở dữ liệu : thực tế đây là điều tôi lo lắng nhất. Tôi đang tìm cách tạo bản dịch Tin tức / Trang / v.v. càng nhanh càng tốt. Có hai bảng cho mỗi mô-đun (ví dụ NewsNews_translations) là một tùy chọn nhưng cảm giác cần nhiều công việc để có được một hệ thống tốt. Một trong những điều tôi đã đưa ra được dựa trên một data versioninghệ thống tôi đã viết: có một tên bảng cơ sở dữ liệu Translations, bảng này có một sự kết hợp độc đáo của language, tablenameprimarykey. Ví dụ: en_En / Tin tức / 1 (Tham khảo phiên bản tiếng Anh của mục Tin tức có ID = 1). Nhưng có hai nhược điểm rất lớn đối với phương pháp này: trước hết bảng này có xu hướng khá dài với nhiều dữ liệu trong cơ sở dữ liệu và thứ hai sẽ là một công việc tồi tệ khi sử dụng thiết lập này để tìm kiếm bảng. Ví dụ: tìm kiếm slug SEO của mục sẽ là một tìm kiếm toàn văn, khá là ngu ngốc. Nhưng mặt khác: đó là một cách nhanh chóng để tạo ra nội dung có thể dịch được trong mỗi bảng rất nhanh, nhưng tôi không tin rằng chuyên gia này vượt trội so với con lừa.
  5. Front-end Work : Ngoài ra front-end sẽ cần một số suy nghĩ. Tất nhiên, chúng tôi sẽ lưu trữ các ngôn ngữ có sẵn trong cơ sở dữ liệu và (kích hoạt) các ngôn ngữ chúng tôi cần. Bằng cách này, tập lệnh có thể tạo ra một danh sách thả xuống để chọn ngôn ngữ và phần cuối có thể tự động quyết định bản dịch nào có thể được thực hiện bằng CMS. Ngôn ngữ được chọn (ví dụ en_EN) sau đó sẽ được sử dụng khi lấy tệp ngôn ngữ để xem hoặc để có bản dịch đúng cho một mục nội dung trên trang web.

Vì vậy, họ có. Ý tưởng của tôi cho đến nay. Chúng thậm chí không bao gồm các tùy chọn bản địa hóa cho ngày, v.v., nhưng vì máy chủ của tôi hỗ trợ PHP5.3.2 + tùy chọn tốt nhất là sử dụng tiện ích mở rộng intl như được giải thích tại đây: http -php-53 / - nhưng điều này sẽ được sử dụng trong bất kỳ sân vận động phát triển nào sau này. Bây giờ vấn đề chính là làm thế nào để có những thông lệ tốt nhất về dịch thuật nội dung trong một trang web.

Ngoài mọi thứ tôi đã giải thích ở đây, tôi vẫn còn một điều nữa mà tôi chưa quyết định, nó có vẻ như là một câu hỏi đơn giản, nhưng thực tế nó đang khiến tôi đau đầu:

Dịch URL? Có nên làm điều này hay không? và theo cách nào?

Vì vậy, nếu tôi có url này: http://www.domain.com/about-usvà tiếng Anh là ngôn ngữ mặc định của tôi. URL này có nên được dịch sang http://www.domain.com/over-onskhi tôi chọn tiếng Hà Lan làm ngôn ngữ của mình không? Hoặc chúng ta nên đi con đường dễ dàng và chỉ cần thay đổi nội dung của trang hiển thị tại /about. Điều cuối cùng dường như không phải là một tùy chọn hợp lệ bởi vì điều đó sẽ tạo ra nhiều phiên bản của cùng một URL, việc lập chỉ mục nội dung này sẽ không đúng cách.

Một lựa chọn khác là sử dụng http://www.domain.com/nl/about-usthay thế. Điều này tạo ra ít nhất một URL duy nhất cho mỗi nội dung. Ngoài ra, điều này sẽ dễ dàng hơn để đi đến một ngôn ngữ khác, ví dụ http://www.domain.com/en/about-usvà URL được cung cấp dễ hiểu hơn cho cả khách truy cập Google và Con người. Sử dụng tùy chọn này, chúng ta sẽ làm gì với các ngôn ngữ mặc định? Ngôn ngữ mặc định có nên loại bỏ ngôn ngữ được chọn theo mặc định? Vì vậy, chuyển hướng http://www.domain.com/en/about-usđến http://www.domain.com/about-us... Trong mắt tôi đây là giải pháp tốt nhất, bởi vì khi CMS được thiết lập chỉ cho một ngôn ngữ thì không cần phải có nhận dạng ngôn ngữ này trong URL.

Và tùy chọn thứ ba là sự kết hợp từ cả hai tùy chọn: sử dụng "không nhận dạng ngôn ngữ" -URL ( http://www.domain.com/about-us) cho ngôn ngữ chính. Và sử dụng URL với một con sên SEO được dịch cho các ngôn ngữ con: http://www.domain.com/nl/over-ons&http://www.domain.com/de/uber-uns

Tôi hy vọng câu hỏi của tôi khiến đầu bạn nứt ra, chắc chắn họ đã bẻ khóa tôi! Nó đã giúp tôi sẵn sàng giải quyết vấn đề ở đây. Đã cho tôi khả năng xem lại các phương pháp tôi đã sử dụng trước đây và ý tưởng tôi đang có cho CMS sắp tới của mình.

Tôi muốn cảm ơn bạn đã dành thời gian để đọc bó văn bản này!

// Edit #1:

Tôi quên đề cập: hàm __ () là bí danh để dịch một chuỗi đã cho. Trong phương thức này rõ ràng nên có một số phương thức dự phòng trong đó văn bản mặc định được tải khi chưa có bản dịch. Nếu bản dịch bị thiếu thì nên chèn hoặc tệp dịch sẽ được tạo lại.


Câu trả lời:


115

Tiền đề của chủ đề

Có ba khía cạnh khác nhau trong một trang web đa ngôn ngữ:

  • giao diện dịch
  • Nội dung
  • định tuyến url

Mặc dù tất cả chúng được kết nối với nhau theo những cách khác nhau, từ quan điểm CMS, chúng được quản lý bằng các yếu tố UI khác nhau và được lưu trữ khác nhau. Bạn dường như tự tin trong việc thực hiện và hiểu biết của bạn về hai người đầu tiên. Câu hỏi là về khía cạnh thứ hai - "Dịch URL? Chúng ta có nên làm điều này hay không? Và theo cách nào?"

URL có thể được làm bằng gì?

Một điều rất quan trọng là, đừng có thích với IDN . Thay vào đó ủng hộ phiên âm (cũng: phiên âm và La tinh hóa). Mặc dù thoạt nhìn IDN có vẻ là tùy chọn khả thi cho các URL quốc tế, nhưng thực tế nó không hoạt động như quảng cáo vì hai lý do:

  • một số trình duyệt sẽ biến các ký tự không phải ASCII như 'ч'hoặc 'ž'thành '%D1%87''%C5%BE'
  • nếu người dùng có chủ đề tùy chỉnh, phông chữ của chủ đề rất có thể không có ký hiệu cho các chữ cái đó

Tôi thực sự đã cố gắng tiếp cận IDN vài năm trước trong một dự án dựa trên Yii (khuôn khổ khủng khiếp, IMHO). Tôi đã gặp cả hai vấn đề nêu trên trước khi tìm giải pháp đó. Ngoài ra, tôi nghi ngờ rằng nó có thể là một vector tấn công.

Tùy chọn có sẵn ... như tôi thấy chúng.

Về cơ bản, bạn có hai lựa chọn, có thể được tóm tắt là:

  • http://site.tld/[:query]: nơi [:query]xác định cả lựa chọn ngôn ngữ và nội dung

  • http://site.tld/[:language]/[:query]: trong đó [:language]một phần của URL xác định lựa chọn ngôn ngữ và [:query]chỉ được sử dụng để xác định nội dung

Truy vấn là và Ω ..

Hãy nói rằng bạn chọn http://site.tld/[:query].

Trong trường hợp đó, bạn có một nguồn ngôn ngữ chính: nội dung của [:query]phân khúc; và hai nguồn bổ sung:

  • giá trị $_COOKIE['lang']cho trình duyệt cụ thể đó
  • danh sách các ngôn ngữ trong tiêu đề Ngôn ngữ chấp nhận HTTP (1) , (2)

Trước tiên, bạn cần khớp truy vấn với một trong các mẫu định tuyến đã xác định (nếu lựa chọn của bạn là Laravel, sau đó đọc tại đây ). Khi kết hợp thành công mẫu bạn cần tìm ngôn ngữ.

Bạn sẽ phải đi qua tất cả các phân đoạn của mẫu. Tìm các bản dịch tiềm năng cho tất cả các phân đoạn đó và xác định ngôn ngữ nào đã được sử dụng. Hai nguồn bổ sung (cookie và tiêu đề) sẽ được sử dụng để giải quyết xung đột định tuyến, khi (không phải "nếu") chúng phát sinh.

Lấy ví dụ : http://site.tld/blog/novinka.

Đó là phiên âm của "блог, новинка", trong tiếng Anh có nghĩa là khoảng "blog", "latest".

Như bạn có thể nhận thấy, trong tiếng Nga "блог" sẽ được phiên âm là "blog". Điều đó có nghĩa là đối với phần đầu tiên của [:query]bạn (trong trường hợp tốt nhất ) sẽ kết thúc với ['en', 'ru']danh sách các ngôn ngữ có thể. Sau đó, bạn đi đoạn tiếp theo - "novinka". Điều đó có thể chỉ có một ngôn ngữ trong danh sách các khả năng : ['ru'].

Khi danh sách có một mục, bạn đã tìm thấy ngôn ngữ thành công.

Nhưng nếu bạn kết thúc với 2 (ví dụ: tiếng Nga và tiếng Ukraina) hoặc nhiều khả năng hơn .. hoặc 0 khả năng, như một trường hợp có thể. Bạn sẽ phải sử dụng cookie và / hoặc tiêu đề để tìm tùy chọn chính xác.

Và nếu thất bại, bạn chọn ngôn ngữ mặc định của trang web.

Ngôn ngữ như tham số

Thay thế là sử dụng URL, có thể được định nghĩa là http://site.tld/[:language]/[:query]. Trong trường hợp này, khi dịch truy vấn, bạn không cần phải đoán ngôn ngữ, vì tại thời điểm đó bạn đã biết nên sử dụng ngôn ngữ nào.

Ngoài ra còn có một nguồn ngôn ngữ thứ cấp: giá trị cookie. Nhưng ở đây không có điểm nào gây rối với tiêu đề Ngôn ngữ chấp nhận, bởi vì bạn không xử lý lượng ngôn ngữ có thể không xác định trong trường hợp "bắt đầu lạnh" (khi người dùng lần đầu mở trang web với truy vấn tùy chỉnh).

Thay vào đó, bạn có 3 tùy chọn đơn giản, ưu tiên:

  1. nếu [:language]phân đoạn được đặt, sử dụng nó
  2. nếu $_COOKIE['lang']được đặt, sử dụng nó
  3. sử dụng ngôn ngữ mặc định

Khi bạn có ngôn ngữ, bạn chỉ cần cố gắng dịch truy vấn và nếu dịch không thành công, hãy sử dụng "giá trị mặc định" cho phân đoạn cụ thể đó (dựa trên kết quả định tuyến).

Đây không phải là một lựa chọn thứ ba sao?

Vâng, về mặt kỹ thuật bạn có thể kết hợp cả hai phương pháp, nhưng điều đó sẽ làm phức tạp quá trình và chỉ chứa những người muốn thay đổi URL bằng tay của http://site.tld/en/newsđể http://site.tld/de/newsvà hy vọng các trang tin tức để thay đổi sang tiếng Đức.

Nhưng ngay cả trường hợp này cũng có thể được giảm thiểu bằng cách sử dụng giá trị cookie (sẽ chứa thông tin về lựa chọn ngôn ngữ trước đó), để thực hiện với ít ma thuật và hy vọng hơn.

Cách tiếp cận nào để sử dụng?

Như bạn có thể đã đoán, tôi muốn giới thiệu http://site.tld/[:language]/[:query]là tùy chọn hợp lý hơn.

Ngoài ra trong tình huống từ thực, bạn sẽ có phần chính thứ 3 trong URL: "title". Như tên của sản phẩm trong cửa hàng trực tuyến hoặc tiêu đề của bài viết trong trang web tin tức.

Thí dụ: http://site.tld/en/news/article/121415/EU-as-global-reserve-currency

Trong trường hợp này '/news/article/121415'sẽ là truy vấn, và 'EU-as-global-reserve-currency'tiêu đề là. Hoàn toàn cho mục đích SEO.

Nó có thể được thực hiện ở Laravel không?

Kinda, nhưng không mặc định.

Tôi không quá quen thuộc với nó, nhưng từ những gì tôi đã thấy, Laravel sử dụng cơ chế định tuyến dựa trên mẫu đơn giản. Để triển khai URL đa ngôn ngữ, có thể bạn sẽ phải mở rộng (các) lớp lõi , vì định tuyến đa ngôn ngữ cần truy cập vào các hình thức lưu trữ khác nhau (cơ sở dữ liệu, bộ đệm và / hoặc tệp cấu hình).

Nó đã được định tuyến. Gì bây giờ?

Kết quả là tất cả bạn sẽ kết thúc với hai mẩu thông tin có giá trị: ngôn ngữ hiện tại và các phân đoạn truy vấn được dịch. Các giá trị này sau đó có thể được sử dụng để gửi đến (các) lớp sẽ tạo ra kết quả.

Về cơ bản, URL sau: http://site.tld/ru/blog/novinka(hoặc phiên bản không có '/ru') được chuyển thành dạng như

$parameters = [
   'language' => 'ru',
   'classname' => 'blog',
   'method' => 'latest',
];

Mà bạn chỉ sử dụng để gửi:

$instance = new {$parameter['classname']};
$instance->{'get'.$parameters['method']}( $parameters );

.. hoặc một số biến thể của nó, tùy thuộc vào việc thực hiện cụ thể.


1
Cảm ơn cho một cái nhìn sâu sắc khác! Rất chu đáo! Tôi đã nghĩ đến việc có tham số ngôn ngữ trong URL. Đây đơn giản là cách tốt nhất để xác định một ngôn ngữ cụ thể, không chỉ cho người dùng mà còn cho mục đích SEO. Trong trường hợp người dùng thay đổi / en / news thành / de / news, ý tưởng của tôi là thực hiện chuyển hướng 301 (vĩnh viễn) sang / de / nachrichten chẳng hạn. Chỉ để đảm bảo mỗi ngôn ngữ chỉ có một URL duy nhất trên mỗi trang (một lần nữa cho mục đích SEO)
Joshua - Pendo

Càng ngày càng khó hơn để chọn câu trả lời hay nhất, hiện tại có khoảng 3/4 câu trả lời xứng đáng với ít nhất một phần của mỗi tiền thưởng. Kết hợp chúng trở thành một câu trả lời chắc chắn cho mọi thứ tôi muốn làm sáng tỏ cùng nhau :)
Joshua - Pendo

Tôi đã xác nhận câu trả lời của bạn để cung cấp cho bạn ít nhất một số đại diện bổ sung cho câu trả lời chi tiết bạn đã cung cấp cho bản dịch URL. Đánh giá cao! Tuy nhiên, tiền thưởng là người trao giải cho người bên dưới bạn vì anh ta trả lời mọi khía cạnh của câu hỏi của tôi theo cách độc lập với nền tảng.
Joshua - Pendo

52

Triển khai i18n mà không có hiệu suất đạt được bằng cách sử dụng bộ xử lý trước theo đề xuất của Thomas Bley

Trong công việc, gần đây chúng tôi đã thực hiện i18n trên một số tài sản của chúng tôi và một trong những điều chúng tôi tiếp tục đấu tranh là hiệu suất xử lý dịch thuật nhanh chóng, sau đó tôi phát hiện ra bài đăng blog tuyệt vời này của Thomas Bley đã truyền cảm hứng cho cách chúng tôi sử dụng i18n để xử lý tải lưu lượng lớn với các vấn đề hiệu suất tối thiểu.

Thay vì gọi các hàm cho mọi hoạt động dịch thuật, như chúng ta biết trong PHP rất tốn kém, chúng tôi xác định các tệp cơ sở của mình bằng trình giữ chỗ, sau đó sử dụng bộ xử lý trước để lưu trữ các tệp đó (chúng tôi lưu trữ thời gian sửa đổi tệp để đảm bảo chúng tôi đang phục vụ nội dung mới nhất mọi lúc).

Thẻ dịch

Thomas sử dụng {tr}{/tr}các thẻ để xác định nơi bắt đầu dịch và kết thúc. Do thực tế là chúng tôi đang sử dụng TWIG, chúng tôi không muốn sử dụng {để tránh nhầm lẫn nên chúng tôi sử dụng [%tr%][%/tr%]thay vào đó. Về cơ bản, nó trông như thế này:

`return [%tr%]formatted_value[%/tr%];`

Lưu ý rằng Thomas đề nghị sử dụng tiếng Anh cơ bản trong tệp. Chúng tôi không làm điều này bởi vì chúng tôi không muốn phải sửa đổi tất cả các tệp dịch nếu chúng tôi thay đổi giá trị bằng tiếng Anh.

Tệp INI

Sau đó, chúng tôi tạo một tệp INI cho mỗi ngôn ngữ, theo định dạng placeholder = translated:

// lang/fr.ini
formatted_value = number_format($value * Model_Exchange::getEurRate(), 2, ',', ' ') . '€'

// lang/en_gb.ini
formatted_value = '£' . number_format($value * Model_Exchange::getStgRate())

// lang/en_us.ini
formatted_value = '$' . number_format($value)

Sẽ thật tầm thường khi cho phép người dùng sửa đổi những thứ này bên trong CMS, chỉ cần lấy bàn phím bằng cách preg_splitbật \nhoặc =làm cho CMS có thể ghi vào các tệp INI.

Thành phần tiền xử lý

Về cơ bản, Thomas đề nghị sử dụng một 'trình biên dịch' đúng lúc (mặc dù, trong thực tế, đó là một bộ tiền xử lý) như thế này để lấy các tệp dịch của bạn và tạo các tệp PHP tĩnh trên đĩa. Bằng cách này, về cơ bản, chúng tôi lưu trữ các tệp đã dịch của chúng tôi thay vì gọi hàm dịch cho mọi chuỗi trong tệp:

// This function was written by Thomas Bley, not by me
function translate($file) {
  $cache_file = 'cache/'.LANG.'_'.basename($file).'_'.filemtime($file).'.php';
  // (re)build translation?
  if (!file_exists($cache_file)) {
    $lang_file = 'lang/'.LANG.'.ini';
    $lang_file_php = 'cache/'.LANG.'_'.filemtime($lang_file).'.php';

    // convert .ini file into .php file
    if (!file_exists($lang_file_php)) {
      file_put_contents($lang_file_php, '<?php $strings='.
        var_export(parse_ini_file($lang_file), true).';', LOCK_EX);
    }
    // translate .php into localized .php file
    $tr = function($match) use (&$lang_file_php) {
      static $strings = null;
      if ($strings===null) require($lang_file_php);
      return isset($strings[ $match[1] ]) ? $strings[ $match[1] ] : $match[1];
    };
    // replace all {t}abc{/t} by tr()
    file_put_contents($cache_file, preg_replace_callback(
      '/\[%tr%\](.*?)\[%\/tr%\]/', $tr, file_get_contents($file)), LOCK_EX);
  }
  return $cache_file;
}

Lưu ý: Tôi không xác minh rằng regex hoạt động, tôi đã không sao chép nó từ máy chủ của công ty chúng tôi, nhưng bạn có thể thấy cách hoạt động.

Cách gọi

Một lần nữa, ví dụ này là của Thomas Bley, không phải từ tôi:

// instead of
require("core/example.php");
echo (new example())->now();

// we write
define('LANG', 'en_us');
require(translate('core/example.php'));
echo (new example())->now();

Chúng tôi lưu trữ ngôn ngữ trong cookie (hoặc biến phiên nếu chúng tôi không thể nhận cookie) và sau đó truy xuất ngôn ngữ đó theo mọi yêu cầu. Bạn có thể kết hợp $_GETthông số này với một tham số tùy chọn để ghi đè ngôn ngữ, nhưng tôi không đề xuất tên miền phụ cho mỗi ngôn ngữ hoặc trang trên mỗi ngôn ngữ vì sẽ khó khăn hơn để xem trang nào phổ biến và sẽ làm giảm giá trị của nội địa liên kết như bạn sẽ có chúng lan truyền hiếm hơn.

Tại sao nên sử dụng phương pháp này?

Chúng tôi thích phương pháp tiền xử lý này vì ba lý do:

  1. Hiệu suất đạt được rất lớn từ việc không gọi cả đống chức năng cho nội dung hiếm khi thay đổi (với hệ thống này, 100 nghìn khách truy cập bằng tiếng Pháp sẽ vẫn chỉ chạy thay thế dịch thuật một lần).
  2. Nó không thêm bất kỳ tải nào vào cơ sở dữ liệu của chúng tôi, vì nó sử dụng các tệp phẳng đơn giản và là một giải pháp thuần túy PHP.
  3. Khả năng sử dụng các biểu thức PHP trong bản dịch của chúng tôi.

Bắt nội dung cơ sở dữ liệu được dịch

Chúng tôi chỉ cần thêm một cột cho nội dung trong cơ sở dữ liệu của chúng tôi được gọi language, sau đó chúng tôi sử dụng một phương thức truy cập cho LANGhằng số mà chúng tôi đã xác định trước đó, vì vậy các cuộc gọi SQL của chúng tôi (sử dụng ZF1, thật đáng buồn) trông như thế này:

$query = select()->from($this->_name)
                 ->where('language = ?', User::getLang())
                 ->where('id       = ?', $articleId)
                 ->limit(1);

Các bài viết của chúng tôi có một khóa chính tổng hợp idlanguagevì vậy bài viết 54có thể tồn tại trong tất cả các ngôn ngữ. Mặc LANGđịnh của chúng tôi en_USnếu không được chỉ định.

Dịch sên URL

Tôi đã kết hợp hai thứ ở đây, một là một hàm trong bootstrap của bạn chấp nhận một $_GETtham số cho ngôn ngữ và ghi đè biến cookie và một thứ khác là định tuyến chấp nhận nhiều sên. Sau đó, bạn có thể làm một cái gì đó như thế này trong định tuyến của bạn:

"/wilkommen" => "/welcome/lang/de"
... etc ...

Chúng có thể được lưu trữ trong một tệp phẳng có thể dễ dàng ghi vào bảng quản trị của bạn. JSON hoặc XML có thể cung cấp một cấu trúc tốt để hỗ trợ chúng.

Ghi chú về một vài lựa chọn khác

Dịch thuật On-The-Fly dựa trên PHP

Tôi không thể thấy rằng những điều này cung cấp bất kỳ lợi thế nào so với các bản dịch được xử lý trước.

Bản dịch dựa trên giao diện người dùng

Từ lâu tôi đã tìm thấy những điều thú vị này, nhưng có một vài cảnh báo. Ví dụ: bạn phải cung cấp cho người dùng toàn bộ danh sách các cụm từ trên trang web của bạn mà bạn dự định dịch, điều này có thể có vấn đề nếu có các khu vực của trang web bạn đang ẩn hoặc không cho phép họ truy cập.

Bạn cũng phải cho rằng tất cả người dùng của bạn đều sẵn sàng và có thể sử dụng Javascript trên trang web của bạn, nhưng theo thống kê của tôi, khoảng 2,5% người dùng của chúng tôi đang chạy mà không có nó (hoặc sử dụng Noscript để chặn các trang web của chúng tôi sử dụng nó) .

Bản dịch dựa trên cơ sở dữ liệu

Tốc độ kết nối cơ sở dữ liệu của PHP không có gì để viết về nhà, và điều này làm tăng thêm chi phí cao khi gọi một hàm trên mỗi cụm từ cần dịch. Các vấn đề về hiệu suất và khả năng mở rộng có vẻ áp đảo với phương pháp này.


Tôi thấy rằng tôi đã nhầm lẫn bạn với "Bản dịch Front-end", ý tôi muốn nói là cách phân tích các chuỗi dịch trên màn hình. Tôi chắc chắn không tìm cách dịch nó về phía khách hàng! Ý tôi là cách dễ nhất để chuyển đổi ngôn ngữ ở mặt trước, nhưng rõ ràng đó là sử dụng cookie hoặc cài đặt người dùng :)
Joshua - Pendo

Ồ, và bởi Cơ sở dữ liệu, tôi đã nhắm đến phương pháp quản lý tất cả các bản dịch, vì vậy giải pháp lý tưởng của tôi sẽ là một back-end viết các bản dịch vào cơ sở dữ liệu theo sau là một hàm tạo ra thành phần tiền xử lý tạo ra PHP tập tin. Why?: đơn giản .. Tôi muốn không bị làm phiền bởi những thay đổi nhỏ trong văn bản, người dùng sẽ có thể tự làm như vậy mà không cần sử dụng trình chỉnh sửa mã và / hoặc chương trình ftp :)
Joshua - Pendo

@PENDO Tôi biết bạn không có nghĩa là bản dịch front-end, đó là một nhận xét được che giấu mỏng manh đối với người dùng đã đề xuất các khung dịch thuật front-end bằng cách sử dụng JS. ;)
Glitch Desire

@PENDO Tôi đồng ý, tôi sẽ sử dụng phụ trợ như bạn đề xuất nhưng thay vì cơ sở dữ liệu tôi sẽ sử dụng tệp phẳng vì lý do hiệu suất. Tất nhiên, đề nghị cốt lõi ở đây là pre-render các mẫu khi thay đổi, do đó bạn có thể thay thế các .INItập tin với một bảng cơ sở dữ liệu 3 cột với placeholder, replacement, language. Phím ghép trên placeholderlanguage. Sau đó, có thêm 2 col với tempfile(đường dẫn đến mẫu) vàmodified (DATETIME).
Glitch Desire

1
@PENDO Cảm ơn. Tôi đã đặt lại 250 và tôi dự định trao giải thưởng cho teresko trong 24 giờ khi trang web cho phép tôi, vì bạn đã chọn cả hai câu trả lời là chính xác và tôi nghĩ rằng một sự phân chia sẽ thể hiện tốt nhất ý định của bạn.
Glitch Desire

15

Tôi đề nghị bạn không phát minh ra một bánh xe và sử dụng danh sách viết tắt của ngôn ngữ gettext và ISO. Bạn đã thấy cách i18n / l10n triển khai trong các CMS hoặc khung phổ biến chưa?

Sử dụng gettext bạn sẽ có một công cụ mạnh mẽ trong đó nhiều trường hợp đã được triển khai như các dạng số nhiều. Trong tiếng Anh, bạn chỉ có 2 lựa chọn: số ít và số nhiều. Nhưng trong tiếng Nga chẳng hạn có 3 hình thức và nó không đơn giản như trong tiếng Anh.

Ngoài ra nhiều dịch giả đã có kinh nghiệm để làm việc với gettext.

Hãy xem CakePHP hoặc Drupal . Cả hai đa ngôn ngữ được kích hoạt. CakePHP là ví dụ về nội địa hóa giao diện và Drupal là ví dụ về dịch nội dung.

Đối với l10n sử dụng cơ sở dữ liệu hoàn toàn không phải là trường hợp. Nó sẽ là tấn trên các truy vấn. Cách tiếp cận tiêu chuẩn là lấy tất cả dữ liệu l10n trong bộ nhớ ở giai đoạn đầu (hoặc trong lần gọi đầu tiên đến chức năng i10n nếu bạn thích tải lười biếng). Nó có thể được đọc từ tệp .po hoặc từ DB tất cả dữ liệu cùng một lúc. Và hơn là chỉ đọc các chuỗi yêu cầu từ mảng.

Nếu bạn cần triển khai công cụ trực tuyến để dịch giao diện, bạn có thể có tất cả dữ liệu đó trong DB nhưng vẫn lưu tất cả dữ liệu vào tệp để làm việc với nó. Để giảm lượng dữ liệu trong bộ nhớ, bạn có thể chia tất cả các tin nhắn / chuỗi đã dịch thành các nhóm và chỉ tải các nhóm mà bạn cần nếu có thể.

Vì vậy, bạn hoàn toàn đúng trong số 3 của bạn. Với một ngoại lệ: thông thường nó là một tệp lớn không phải là tệp trên mỗi bộ điều khiển. Bởi vì nó là tốt nhất cho hiệu suất để mở một tập tin. Bạn có thể biết rằng một số ứng dụng web tải cao biên dịch tất cả mã PHP trong một tệp để tránh các thao tác tệp khi bao gồm / yêu cầu được gọi.

Về URL. Google gián tiếp đề xuất sử dụng bản dịch:

để chỉ rõ nội dung tiếng Pháp: http://example.ca/fr/vélo-de-montagne.html

Ngoài ra tôi nghĩ bạn cần chuyển hướng người dùng đến tiền tố ngôn ngữ mặc định, vd http://examlpe.com/about-us sẽ chuyển hướng đến http://examlpe.com/en/about-us Nhưng nếu trang web của bạn chỉ sử dụng một ngôn ngữ để bạn không cần tiền tố nào cả.

Kiểm tra: http://www.audiomicro.com/trailer-hit-impact-psychodrama-sound-effects-836925 http://nl.audiomicro.com/aanhangwagen-hit-effect-psychodrama-geluidseffecten-836925 http: / /de.audiomicro.com/anhanger-hit-auswirkungen-psychodrama-sound-effekte-836925

Dịch nội dung là nhiệm vụ khó khăn hơn. Tôi nghĩ rằng sẽ có một số khác biệt với các loại nội dung khác nhau, ví dụ như bài viết, mục menu, v.v. Nhưng trong # 4, bạn đang đi đúng hướng. Hãy xem trong Drupal để có thêm ý tưởng. Nó có lược đồ DB đủ rõ ràng và giao diện đủ tốt để dịch. Giống như bạn tạo bài viết và chọn ngôn ngữ cho nó. Và sau này bạn có thể dịch nó sang các ngôn ngữ khác.

Giao diện dịch thuật Drupal

Tôi nghĩ đó không phải là vấn đề với sên URL. Bạn chỉ có thể tạo bảng riêng cho sên và đó sẽ là quyết định đúng đắn. Ngoài ra, sử dụng các chỉ mục đúng, không có vấn đề gì với bảng truy vấn ngay cả với lượng dữ liệu khổng lồ. Và nó không phải là tìm kiếm toàn văn bản mà là khớp chuỗi nếu sẽ sử dụng kiểu dữ liệu varchar cho slug và bạn cũng có thể có một chỉ mục trên trường đó.

PS Xin lỗi, tiếng Anh của tôi không hoàn hảo.


Cảm ơn đã dành thời gian trả lời câu hỏi của tôi. Tiếng Anh của bạn đủ tốt để tôi hiểu! Tôi sẽ +1 bạn vì những nỗ lực của bạn!
Joshua - Pendo

Yaroslav, một lần nữa, cảm ơn câu trả lời của bạn. Tuy nhiên tôi đã đi với 2 câu trả lời khác là nơi hoàn thiện hơn một chút và giải thích các phương thức được sử dụng đằng sau mã thay vì chỉ ra nó đã có sẵn.
Joshua - Pendo

2
Không vấn đề gì. Quả thực là câu trả lời đầy đủ và thú vị hơn để đọc cho tôi quá. Nhưng tôi hy vọng bạn cũng có một cái gì đó hữu ích từ câu trả lời của tôi.
Yaroslav

12

Nó phụ thuộc vào bao nhiêu nội dung trang web của bạn có. Lúc đầu, tôi đã sử dụng một cơ sở dữ liệu như tất cả những người khác ở đây, nhưng nó có thể tốn thời gian để kịch bản tất cả các hoạt động của cơ sở dữ liệu. Tôi không nói rằng đây là một phương pháp lý tưởng và đặc biệt là nếu bạn có nhiều văn bản, nhưng nếu bạn muốn làm nhanh mà không cần sử dụng cơ sở dữ liệu, thì phương pháp này có thể hoạt động, tuy nhiên, bạn không thể cho phép người dùng nhập dữ liệu sẽ được sử dụng như tập tin dịch. Nhưng nếu bạn tự thêm các bản dịch, nó sẽ hoạt động:

Giả sử bạn có văn bản này:

Welcome!

Bạn có thể nhập dữ liệu này vào cơ sở dữ liệu bằng các bản dịch, nhưng bạn cũng có thể thực hiện việc này:

$welcome = array(
"English"=>"Welcome!",
"German"=>"Willkommen!",
"French"=>"Bienvenue!",
"Turkish"=>"Hoşgeldiniz!",
"Russian"=>"Добро пожаловать!",
"Dutch"=>"Welkom!",
"Swedish"=>"Välkommen!",
"Basque"=>"Ongietorri!",
"Spanish"=>"Bienvenito!"
"Welsh"=>"Croeso!");

Bây giờ, nếu trang web của bạn sử dụng cookie, bạn có ví dụ này:

$_COOKIE['language'];

Để làm cho nó dễ dàng, hãy chuyển đổi nó thành một mã có thể dễ dàng sử dụng:

$language=$_COOKIE['language'];

Nếu ngôn ngữ cookie của bạn là tiếng Wales và bạn có đoạn mã này:

echo $welcome[$language];

Kết quả của việc này sẽ là:

Croeso!

Nếu bạn cần thêm nhiều bản dịch cho trang web của mình và cơ sở dữ liệu quá tốn kém, sử dụng một mảng có thể là một giải pháp lý tưởng.


1
Đây là không - nơi gần câu trả lời tôi đã yêu cầu. Ngoài ra, thay vì có tất cả các ngôn ngữ có sẵn trên mỗi trang, tốt hơn bạn nên tạo các tệp như lang.en.phpđược bao gồm và sử dụng $lang['welcome']được khai báo trong mỗi tệp.
Joshua - Pendo

7

Tôi sẽ đề nghị bạn không thực sự phụ thuộc vào cơ sở dữ liệu để dịch nó có thể thực sự là một nhiệm vụ lộn xộn và có thể là một vấn đề cực đoan trong trường hợp mã hóa dữ liệu.

Tôi đã phải đối mặt với vấn đề tương tự trong khi trước đây và viết theo lớp để giải quyết vấn đề của tôi

Đối tượng: Địa điểm \ Địa điểm

<?php

  namespace Locale;

  class Locale{

// Following array stolen from Zend Framework
public $country_to_locale = array(
    'AD' => 'ca_AD',
    'AE' => 'ar_AE',
    'AF' => 'fa_AF',
    'AG' => 'en_AG',
    'AI' => 'en_AI',
    'AL' => 'sq_AL',
    'AM' => 'hy_AM',
    'AN' => 'pap_AN',
    'AO' => 'pt_AO',
    'AQ' => 'und_AQ',
    'AR' => 'es_AR',
    'AS' => 'sm_AS',
    'AT' => 'de_AT',
    'AU' => 'en_AU',
    'AW' => 'nl_AW',
    'AX' => 'sv_AX',
    'AZ' => 'az_Latn_AZ',
    'BA' => 'bs_BA',
    'BB' => 'en_BB',
    'BD' => 'bn_BD',
    'BE' => 'nl_BE',
    'BF' => 'mos_BF',
    'BG' => 'bg_BG',
    'BH' => 'ar_BH',
    'BI' => 'rn_BI',
    'BJ' => 'fr_BJ',
    'BL' => 'fr_BL',
    'BM' => 'en_BM',
    'BN' => 'ms_BN',
    'BO' => 'es_BO',
    'BR' => 'pt_BR',
    'BS' => 'en_BS',
    'BT' => 'dz_BT',
    'BV' => 'und_BV',
    'BW' => 'en_BW',
    'BY' => 'be_BY',
    'BZ' => 'en_BZ',
    'CA' => 'en_CA',
    'CC' => 'ms_CC',
    'CD' => 'sw_CD',
    'CF' => 'fr_CF',
    'CG' => 'fr_CG',
    'CH' => 'de_CH',
    'CI' => 'fr_CI',
    'CK' => 'en_CK',
    'CL' => 'es_CL',
    'CM' => 'fr_CM',
    'CN' => 'zh_Hans_CN',
    'CO' => 'es_CO',
    'CR' => 'es_CR',
    'CU' => 'es_CU',
    'CV' => 'kea_CV',
    'CX' => 'en_CX',
    'CY' => 'el_CY',
    'CZ' => 'cs_CZ',
    'DE' => 'de_DE',
    'DJ' => 'aa_DJ',
    'DK' => 'da_DK',
    'DM' => 'en_DM',
    'DO' => 'es_DO',
    'DZ' => 'ar_DZ',
    'EC' => 'es_EC',
    'EE' => 'et_EE',
    'EG' => 'ar_EG',
    'EH' => 'ar_EH',
    'ER' => 'ti_ER',
    'ES' => 'es_ES',
    'ET' => 'en_ET',
    'FI' => 'fi_FI',
    'FJ' => 'hi_FJ',
    'FK' => 'en_FK',
    'FM' => 'chk_FM',
    'FO' => 'fo_FO',
    'FR' => 'fr_FR',
    'GA' => 'fr_GA',
    'GB' => 'en_GB',
    'GD' => 'en_GD',
    'GE' => 'ka_GE',
    'GF' => 'fr_GF',
    'GG' => 'en_GG',
    'GH' => 'ak_GH',
    'GI' => 'en_GI',
    'GL' => 'iu_GL',
    'GM' => 'en_GM',
    'GN' => 'fr_GN',
    'GP' => 'fr_GP',
    'GQ' => 'fan_GQ',
    'GR' => 'el_GR',
    'GS' => 'und_GS',
    'GT' => 'es_GT',
    'GU' => 'en_GU',
    'GW' => 'pt_GW',
    'GY' => 'en_GY',
    'HK' => 'zh_Hant_HK',
    'HM' => 'und_HM',
    'HN' => 'es_HN',
    'HR' => 'hr_HR',
    'HT' => 'ht_HT',
    'HU' => 'hu_HU',
    'ID' => 'id_ID',
    'IE' => 'en_IE',
    'IL' => 'he_IL',
    'IM' => 'en_IM',
    'IN' => 'hi_IN',
    'IO' => 'und_IO',
    'IQ' => 'ar_IQ',
    'IR' => 'fa_IR',
    'IS' => 'is_IS',
    'IT' => 'it_IT',
    'JE' => 'en_JE',
    'JM' => 'en_JM',
    'JO' => 'ar_JO',
    'JP' => 'ja_JP',
    'KE' => 'en_KE',
    'KG' => 'ky_Cyrl_KG',
    'KH' => 'km_KH',
    'KI' => 'en_KI',
    'KM' => 'ar_KM',
    'KN' => 'en_KN',
    'KP' => 'ko_KP',
    'KR' => 'ko_KR',
    'KW' => 'ar_KW',
    'KY' => 'en_KY',
    'KZ' => 'ru_KZ',
    'LA' => 'lo_LA',
    'LB' => 'ar_LB',
    'LC' => 'en_LC',
    'LI' => 'de_LI',
    'LK' => 'si_LK',
    'LR' => 'en_LR',
    'LS' => 'st_LS',
    'LT' => 'lt_LT',
    'LU' => 'fr_LU',
    'LV' => 'lv_LV',
    'LY' => 'ar_LY',
    'MA' => 'ar_MA',
    'MC' => 'fr_MC',
    'MD' => 'ro_MD',
    'ME' => 'sr_Latn_ME',
    'MF' => 'fr_MF',
    'MG' => 'mg_MG',
    'MH' => 'mh_MH',
    'MK' => 'mk_MK',
    'ML' => 'bm_ML',
    'MM' => 'my_MM',
    'MN' => 'mn_Cyrl_MN',
    'MO' => 'zh_Hant_MO',
    'MP' => 'en_MP',
    'MQ' => 'fr_MQ',
    'MR' => 'ar_MR',
    'MS' => 'en_MS',
    'MT' => 'mt_MT',
    'MU' => 'mfe_MU',
    'MV' => 'dv_MV',
    'MW' => 'ny_MW',
    'MX' => 'es_MX',
    'MY' => 'ms_MY',
    'MZ' => 'pt_MZ',
    'NA' => 'kj_NA',
    'NC' => 'fr_NC',
    'NE' => 'ha_Latn_NE',
    'NF' => 'en_NF',
    'NG' => 'en_NG',
    'NI' => 'es_NI',
    'NL' => 'nl_NL',
    'NO' => 'nb_NO',
    'NP' => 'ne_NP',
    'NR' => 'en_NR',
    'NU' => 'niu_NU',
    'NZ' => 'en_NZ',
    'OM' => 'ar_OM',
    'PA' => 'es_PA',
    'PE' => 'es_PE',
    'PF' => 'fr_PF',
    'PG' => 'tpi_PG',
    'PH' => 'fil_PH',
    'PK' => 'ur_PK',
    'PL' => 'pl_PL',
    'PM' => 'fr_PM',
    'PN' => 'en_PN',
    'PR' => 'es_PR',
    'PS' => 'ar_PS',
    'PT' => 'pt_PT',
    'PW' => 'pau_PW',
    'PY' => 'gn_PY',
    'QA' => 'ar_QA',
    'RE' => 'fr_RE',
    'RO' => 'ro_RO',
    'RS' => 'sr_Cyrl_RS',
    'RU' => 'ru_RU',
    'RW' => 'rw_RW',
    'SA' => 'ar_SA',
    'SB' => 'en_SB',
    'SC' => 'crs_SC',
    'SD' => 'ar_SD',
    'SE' => 'sv_SE',
    'SG' => 'en_SG',
    'SH' => 'en_SH',
    'SI' => 'sl_SI',
    'SJ' => 'nb_SJ',
    'SK' => 'sk_SK',
    'SL' => 'kri_SL',
    'SM' => 'it_SM',
    'SN' => 'fr_SN',
    'SO' => 'sw_SO',
    'SR' => 'srn_SR',
    'ST' => 'pt_ST',
    'SV' => 'es_SV',
    'SY' => 'ar_SY',
    'SZ' => 'en_SZ',
    'TC' => 'en_TC',
    'TD' => 'fr_TD',
    'TF' => 'und_TF',
    'TG' => 'fr_TG',
    'TH' => 'th_TH',
    'TJ' => 'tg_Cyrl_TJ',
    'TK' => 'tkl_TK',
    'TL' => 'pt_TL',
    'TM' => 'tk_TM',
    'TN' => 'ar_TN',
    'TO' => 'to_TO',
    'TR' => 'tr_TR',
    'TT' => 'en_TT',
    'TV' => 'tvl_TV',
    'TW' => 'zh_Hant_TW',
    'TZ' => 'sw_TZ',
    'UA' => 'uk_UA',
    'UG' => 'sw_UG',
    'UM' => 'en_UM',
    'US' => 'en_US',
    'UY' => 'es_UY',
    'UZ' => 'uz_Cyrl_UZ',
    'VA' => 'it_VA',
    'VC' => 'en_VC',
    'VE' => 'es_VE',
    'VG' => 'en_VG',
    'VI' => 'en_VI',
    'VN' => 'vn_VN',
    'VU' => 'bi_VU',
    'WF' => 'wls_WF',
    'WS' => 'sm_WS',
    'YE' => 'ar_YE',
    'YT' => 'swb_YT',
    'ZA' => 'en_ZA',
    'ZM' => 'en_ZM',
    'ZW' => 'sn_ZW'
);

/**
 * Store the transaltion for specific languages
 *
 * @var array
 */
protected $translation = array();

/**
 * Current locale
 *
 * @var string
 */
protected $locale;

/**
 * Default locale
 *
 * @var string
 */
protected $default_locale;

/**
 *
 * @var string
 */
protected $locale_dir;

/**
 * Construct.
 *
 *
 * @param string $locale_dir            
 */
public function __construct($locale_dir)
{
    $this->locale_dir = $locale_dir;
}

/**
 * Set the user define localte
 *
 * @param string $locale            
 */
public function setLocale($locale = null)
{
    $this->locale = $locale;

    return $this;
}

/**
 * Get the user define locale
 *
 * @return string
 */
public function getLocale()
{
    return $this->locale;
}

/**
 * Get the Default locale
 *
 * @return string
 */
public function getDefaultLocale()
{
    return $this->default_locale;
}

/**
 * Set the default locale
 *
 * @param string $locale            
 */
public function setDefaultLocale($locale)
{
    $this->default_locale = $locale;

    return $this;
}

/**
 * Determine if transltion exist or translation key exist
 *
 * @param string $locale            
 * @param string $key            
 * @return boolean
 */
public function hasTranslation($locale, $key = null)
{
    if (null == $key && isset($this->translation[$locale])) {
        return true;
    } elseif (isset($this->translation[$locale][$key])) {
        return true;
    }

    return false;
}

/**
 * Get the transltion for required locale or transtion for key
 *
 * @param string $locale            
 * @param string $key            
 * @return array
 */
public function getTranslation($locale, $key = null)
{
    if (null == $key && $this->hasTranslation($locale)) {
        return $this->translation[$locale];
    } elseif ($this->hasTranslation($locale, $key)) {
        return $this->translation[$locale][$key];
    }

    return array();
}

/**
 * Set the transtion for required locale
 *
 * @param string $locale
 *            Language code
 * @param string $trans
 *            translations array
 */
public function setTranslation($locale, $trans = array())
{
    $this->translation[$locale] = $trans;
}

/**
 * Remove transltions for required locale
 *
 * @param string $locale            
 */
public function removeTranslation($locale = null)
{
    if (null === $locale) {
        unset($this->translation);
    } else {
        unset($this->translation[$locale]);
    }
}

/**
 * Initialize locale
 *
 * @param string $locale            
 */
public function init($locale = null, $default_locale = null)
{
    // check if previously set locale exist or not
    $this->init_locale();
    if ($this->locale != null) {
        return;
    }

    if ($locale == null || (! preg_match('#^[a-z]+_[a-zA-Z_]+$#', $locale) && ! preg_match('#^[a-z]+_[a-zA-Z]+_[a-zA-Z_]+$#', $locale))) {
        $this->detectLocale();
    } else {
        $this->locale = $locale;
    }

    $this->init_locale();
}

/**
 * Attempt to autodetect locale
 *
 * @return void
 */
private function detectLocale()
{
    $locale = false;

    // GeoIP
    if (function_exists('geoip_country_code_by_name') && isset($_SERVER['REMOTE_ADDR'])) {

        $country = geoip_country_code_by_name($_SERVER['REMOTE_ADDR']);

        if ($country) {

            $locale = isset($this->country_to_locale[$country]) ? $this->country_to_locale[$country] : false;
        }
    }

    // Try detecting locale from browser headers
    if (! $locale) {

        if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {

            $languages = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);

            foreach ($languages as $lang) {

                $lang = str_replace('-', '_', trim($lang));

                if (strpos($lang, '_') === false) {

                    if (isset($this->country_to_locale[strtoupper($lang)])) {

                        $locale = $this->country_to_locale[strtoupper($lang)];
                    }
                } else {

                    $lang = explode('_', $lang);

                    if (count($lang) == 3) {
                        // language_Encoding_COUNTRY
                        $this->locale = strtolower($lang[0]) . ucfirst($lang[1]) . strtoupper($lang[2]);
                    } else {
                        // language_COUNTRY
                        $this->locale = strtolower($lang[0]) . strtoupper($lang[1]);
                    }

                    return;
                }
            }
        }
    }

    // Resort to default locale specified in config file
    if (! $locale) {
        $this->locale = $this->default_locale;
    }
}

/**
 * Check if config for selected locale exists
 *
 * @return void
 */
private function init_locale()
{
    if (! file_exists(sprintf('%s/%s.php', $this->locale_dir, $this->locale))) {
        $this->locale = $this->default_locale;
    }
}

/**
 * Load a Transtion into array
 *
 * @return void
 */
private function loadTranslation($locale = null, $force = false)
{
    if ($locale == null)
        $locale = $this->locale;

    if (! $this->hasTranslation($locale)) {
        $this->setTranslation($locale, include (sprintf('%s/%s.php', $this->locale_dir, $locale)));
    }
}

/**
 * Translate a key
 *
 * @param
 *            string Key to be translated
 * @param
 *            string optional arguments
 * @return string
 */
public function translate($key)
{
    $this->init();
    $this->loadTranslation($this->locale);

    if (! $this->hasTranslation($this->locale, $key)) {

        if ($this->locale !== $this->default_locale) {

            $this->loadTranslation($this->default_locale);

            if ($this->hasTranslation($this->default_locale, $key)) {

                $translation = $this->getTranslation($this->default_locale, $key);
            } else {
                // return key as it is or log error here
                return $key;
            }
        } else {
            return $key;
        }
    } else {
        $translation = $this->getTranslation($this->locale, $key);
    }
    // Replace arguments
    if (false !== strpos($translation, '{a:')) {
        $replace = array();
        $args = func_get_args();
        for ($i = 1, $max = count($args); $i < $max; $i ++) {
            $replace['{a:' . $i . '}'] = $args[$i];
        }
        // interpolate replacement values into the messsage then return
        return strtr($translation, $replace);
    }

    return $translation;
  }
}

Sử dụng

 <?php
    ## /locale/en.php

    return array(
       'name' => 'Hello {a:1}'
       'name_full' => 'Hello {a:1} {a:2}'
   );

$locale = new Locale(__DIR__ . '/locale');
$locale->setLocale('en');// load en.php from locale dir
//want to work with auto detection comment $locale->setLocale('en');

echo $locale->translate('name', 'Foo');
echo $locale->translate('name', 'Foo', 'Bar');

Làm thế nào nó hoạt động

{a:1}được thay thế bởi đối số 1 được truyền cho phương thức Locale::translate('key_name','arg1') {a:2}được thay thế bằng đối số thứ 2 được truyền cho phương thứcLocale::translate('key_name','arg1','arg2')

Cách phát hiện hoạt động

  • Theo mặc định nếu geoipđược cài đặt thì nó sẽ trả về mã quốc gia geoip_country_code_by_namevà nếu Geoip không được cài đặt dự phòng cho HTTP_ACCEPT_LANGUAGEtiêu đề

Làm thế nào một cơ sở dữ liệu sẽ được lộn xộn? Bởi vì các nhân vật có thể trong các ngôn ngữ khác nhau? Cho đến nay tôi chủ yếu có các trang web tiếng Anh, tiếng Pháp, tiếng Hà Lan, tiếng Đức nên hiện tại không có vấn đề gì. Cảm ơn câu trả lời, nhưng vì nó chỉ là một phần của câu trả lời nên nó sẽ không giành được tiền thưởng.
Joshua - Pendo

Tôi đoán rằng câu hỏi của bạn chỉ hữu ích với bạn, chỉ có một số người sẽ cân nhắc sử dụng các ngôn ngữ như tiếng Hindi, tiếng Thái, tiếng Trung và tiếng Ả Rập (những ngôn ngữ này sẽ mất thêm 1 byte để thể hiện một ký tự) đối với các ngôn ngữ bạn yêu cầu. nếu bạn đang sử dụng db thì utf8_general_ciđối chiếu là cách thích hợp để làm điều đó.
Shushant

Tôi đồng ý, tôi có một chút theo dõi mình ở đó. Cảm ơn bạn đã chỉ ra, các ký tự nhiều bit cũng đủ quan trọng để được đề cập trong câu hỏi này :)
Joshua - Pendo

5

Chỉ cần một câu trả lời phụ: Hoàn toàn sử dụng các url được dịch với một định danh ngôn ngữ ở phía trước chúng: http://www.domain.com/nl/over-ons
giải pháp lai có xu hướng trở nên phức tạp, vì vậy tôi sẽ chỉ sử dụng nó. Tại sao? Nguyên nhân là url cần thiết cho SEO.

Về bản dịch db: Số lượng ngôn ngữ ít nhiều cố định? Hay khá khó đoán và năng động? Nếu nó được sửa, tôi sẽ chỉ thêm các cột mới, nếu không thì đi với nhiều bảng.

Nhưng nói chung, tại sao không sử dụng Drupal? Tôi biết mọi người đều muốn xây dựng CMS của riêng mình vì nó nhanh hơn, gọn hơn, v.v. Nhưng đó thực sự là một ý tưởng tồi!


1
Cảm ơn câu trả lời của bạn. Lý do tôi không muốn sử dụng Drupal / Joomla rất đơn giản: Tôi muốn đảm bảo rằng tôi biết tất cả các hệ thống trong và ngoài hệ thống của mình, cách xây dựng mã (và quan trọng: không được xây dựng bởi 300 lập trình viên) . Tôi đã có quá nhiều lý do để không chọn nguồn mở. Bên cạnh đó, tôi muốn công ty của mình trở thành một nhân tố quan trọng đối với khách hàng của mình, thật tệ khi họ có thể đến bất kỳ nhà phát triển nào khác và bỏ lại tôi mà không có gì.
Joshua - Pendo

7
Tôi nghĩ rằng tất cả những lý do này đang tranh chấp trong hàng tấn bài viết. Khách hàng của bạn hy vọng sẽ không chọn bạn chính xác vì bạn có một CMS độc quyền mà không ai khác có thể duy trì. Nhưng dù sao, đó là một cuộc thảo luận hoàn toàn khác.
Rém

1
Tôi hiểu quan điểm của bạn, tôi vẫn thích một hệ thống mà tôi biết tất cả mọi thứ và tôi không cảm thấy bất cứ điều gì khi dựa vào bất cứ ai làm việc khi tôi sử dụng plugin.
Joshua - Pendo

1
Bên cạnh đó, tôi có xu hướng ghi chép lại công việc của mình đủ tốt, vì tôi là một người "quân đội một người" làm việc cho tôi nên không có thời gian khó khăn để làm quen với hệ thống.
Joshua - Pendo

Ý tưởng tồi là chọn Drupal và thậm chí google nói rằng họ không quan tâm nếu url được dịch hay không. Nó phải chứa một định danh miền địa phương mặc dù.
không xác định

5

Tôi sẽ không cố gắng để tinh chỉnh các câu trả lời đã được đưa ra. Thay vào đó tôi sẽ nói với bạn về cách khung OOP PHP của riêng tôi xử lý các bản dịch.

Trong nội bộ, khung của tôi sử dụng các mã như en, fr, es, cn, v.v. Một mảng chứa các ngôn ngữ được trang web hỗ trợ: mảng ('en', 'fr', 'es', 'cn') Mã ngôn ngữ được truyền qua $ _GET (lang = fr) và nếu không được thông qua hoặc không hợp lệ, nó sẽ không được thông qua được đặt thành ngôn ngữ đầu tiên trong mảng. Vì vậy, bất cứ lúc nào trong quá trình thực hiện chương trình và ngay từ đầu, ngôn ngữ hiện tại đã được biết đến.

Rất hữu ích để hiểu loại nội dung cần được dịch trong một ứng dụng thông thường:

1) thông báo lỗi từ các lớp (hoặc mã thủ tục) 2) thông báo không lỗi từ các lớp (hoặc mã thủ tục) 3) nội dung trang (thường lưu trữ trong cơ sở dữ liệu) 4) chuỗi trên toàn trang web (như tên trang web) 5) script- chuỗi cụ thể

Loại đầu tiên là đơn giản để hiểu. Về cơ bản, chúng ta đang nói về các thông điệp như "không thể kết nối với cơ sở dữ liệu ...". Những thông báo này chỉ cần được tải khi xảy ra lỗi. Lớp người quản lý của tôi nhận được một cuộc gọi từ các lớp khác và sử dụng thông tin được truyền dưới dạng tham số chỉ đơn giản là đi đến thư mục lớp có liên quan và truy xuất tệp lỗi.

Loại thông báo lỗi thứ hai giống như các thông báo bạn nhận được khi xác thực một biểu mẫu bị sai. ("Bạn không thể để ... trống" hoặc "vui lòng chọn mật khẩu có nhiều hơn 5 ký tự"). Các chuỗi cần phải được tải trước khi lớp chạy. Tôi biết cái gì là

Đối với nội dung trang thực tế, tôi sử dụng một bảng cho mỗi ngôn ngữ, mỗi bảng được tiền tố bởi mã cho ngôn ngữ. Vì vậy, en_content là bảng có nội dung tiếng Anh, es_content dành cho Tây Ban Nha, cn_content cho Trung Quốc và fr_content là nội dung của Pháp.

Loại chuỗi thứ tư có liên quan trên toàn bộ trang web của bạn. Điều này được tải thông qua một tệp cấu hình có tên sử dụng mã cho ngôn ngữ, đó là en_lang.php, es_lang.php, v.v. Trong tệp ngôn ngữ toàn cầu, bạn sẽ cần tải các ngôn ngữ đã dịch như mảng ('Tiếng Anh', 'Tiếng Trung', 'Tiếng Tây Ban Nha', 'Tiếng Pháp') trong tệp và mảng toàn cầu tiếng Anh ('Anglais', 'Chinois', ' Espagnol ',' Francais ') trong tập tin tiếng Pháp. Vì vậy, khi bạn điền vào danh sách thả xuống để chọn ngôn ngữ, nó sẽ ở đúng ngôn ngữ;)

Cuối cùng, bạn có các chuỗi đặc trưng cho kịch bản. Vì vậy, nếu bạn viết một ứng dụng nấu ăn, nó có thể là "Lò của bạn không đủ nóng".

Trong chu kỳ ứng dụng của tôi, tệp ngôn ngữ toàn cầu được tải trước tiên. Ở đó, bạn sẽ tìm thấy không chỉ các chuỗi toàn cầu (như "Trang web của Jack") mà còn có các cài đặt cho một số lớp. Về cơ bản bất cứ điều gì phụ thuộc vào ngôn ngữ hoặc văn hóa. Một số chuỗi trong đó bao gồm mặt nạ cho ngày (MMDDYYYY hoặc DDMMYYYY) hoặc Mã ngôn ngữ ISO. Trong tệp ngôn ngữ chính, tôi bao gồm các chuỗi cho các lớp riêng lẻ vì có rất ít trong số chúng.

Tệp ngôn ngữ thứ hai và cuối cùng được đọc từ đĩa là tệp ngôn ngữ tập lệnh. lang_en_home_welcome.php là tệp ngôn ngữ cho tập lệnh home / welcome. Một tập lệnh được xác định bởi một chế độ (nhà) và một hành động (hoan nghênh). Mỗi tập lệnh có thư mục riêng với tập tin cấu hình và lang.

Kịch bản kéo nội dung từ cơ sở dữ liệu đặt tên bảng nội dung như được giải thích ở trên.

Nếu có lỗi xảy ra, người quản lý sẽ biết nơi nhận tệp lỗi phụ thuộc ngôn ngữ. Tập tin đó chỉ được tải trong trường hợp có lỗi.

Vì vậy, kết luận là rõ ràng. Hãy suy nghĩ về các vấn đề dịch thuật trước khi bạn bắt đầu phát triển một ứng dụng hoặc khung. Bạn cũng cần một quy trình phát triển kết hợp các bản dịch. Với khuôn khổ của tôi, tôi phát triển toàn bộ trang web bằng tiếng Anh và sau đó dịch tất cả các tệp có liên quan.

Chỉ là một từ cuối cùng nhanh chóng trên cách thực hiện các chuỗi dịch. Khung của tôi có một trình quản lý $ toàn cầu duy nhất, chạy các dịch vụ có sẵn cho bất kỳ dịch vụ nào khác. Vì vậy, ví dụ dịch vụ biểu mẫu được giữ dịch vụ html và sử dụng nó để viết html. Một trong những dịch vụ trên hệ thống của tôi là dịch vụ dịch thuật. $ translator-> set ($ service, $ code, $ string) đặt một chuỗi cho ngôn ngữ hiện tại. Các tập tin ngôn ngữ là một danh sách các tuyên bố như vậy. $ translator-> get ($ service, $ code) lấy chuỗi dịch. Mã $ có thể là số như 1 hoặc chuỗi như 'no_connection'. Không thể có xung đột giữa các dịch vụ vì mỗi dịch vụ có không gian tên riêng trong vùng dữ liệu của người dịch.

Tôi đăng bài này lên đây với hy vọng nó sẽ cứu ai đó nhiệm vụ sáng tạo lại cái bánh xe như tôi đã phải làm vài năm trước.


4

Tôi đã có cùng một vấn đề trước đây, trước khi bắt đầu sử dụng khung Symfony .

  1. Chỉ cần sử dụng hàm __ () có đường kính pageId (hoặc objectId, objectTable được mô tả trong # 2), ngôn ngữ đích và một tham số tùy chọn của ngôn ngữ dự phòng (mặc định). Ngôn ngữ mặc định có thể được đặt trong một số cấu hình chung để có cách dễ dàng hơn để thay đổi ngôn ngữ này sau này.

  2. Để lưu trữ nội dung trong cơ sở dữ liệu tôi đã sử dụng cấu trúc sau: (pageId, ngôn ngữ, nội dung, biến).

    • pageId sẽ là một FK cho trang của bạn mà bạn muốn dịch. nếu bạn có các đối tượng khác, như tin tức, phòng trưng bày hoặc bất cứ thứ gì, chỉ cần chia nó thành 2 trường objectId, objectTable.

    • ngôn ngữ - rõ ràng là nó sẽ lưu trữ chuỗi ngôn ngữ ISO EN_en, LT_lt, EN_us, v.v.

    • nội dung - văn bản bạn muốn dịch cùng với các ký tự đại diện để thay thế biến. Ví dụ "Xin chào ông %% tên %%. Số dư tài khoản của bạn là %% số dư %%."

    • các biến - các biến được mã hóa json. PHP cung cấp các hàm để phân tích nhanh những thứ này. Ví dụ "tên: Laurynas, số dư: 15,23".

    • bạn cũng đề cập đến lĩnh vực sên. bạn có thể tự do thêm nó vào bảng này chỉ để có một cách nhanh chóng để tìm kiếm nó.

  3. Các cuộc gọi cơ sở dữ liệu của bạn phải được giảm đến mức tối thiểu với bộ nhớ đệm các bản dịch. Nó phải được lưu trữ trong mảng PHP, bởi vì nó là cấu trúc nhanh nhất trong ngôn ngữ PHP. Làm thế nào bạn sẽ làm cho bộ nhớ đệm này là tùy thuộc vào bạn. Theo kinh nghiệm của tôi, bạn nên có một thư mục cho mỗi ngôn ngữ được hỗ trợ và một mảng cho mỗi pageId. Bộ nhớ cache sẽ được xây dựng lại sau khi bạn cập nhật bản dịch. CHỈ mảng thay đổi sẽ được tái tạo.

  4. tôi nghĩ rằng tôi đã trả lời rằng trong # 2

  5. ý tưởng của bạn là hoàn toàn hợp lý. Điều này là khá đơn giản và tôi nghĩ sẽ không làm cho bạn bất kỳ vấn đề.

URL nên được dịch bằng cách sử dụng các sên được lưu trữ trong bảng dịch.

Từ cuối cùng

luôn luôn tốt để nghiên cứu các thực tiễn tốt nhất, nhưng không phát minh lại bánh xe. chỉ cần lấy và sử dụng các thành phần từ các khung công tác nổi tiếng và sử dụng chúng.

hãy xem thành phần dịch thuật Symfony . Nó có thể là một cơ sở mã tốt cho bạn.


Cảm ơn vì nhận xét, lấy +1 cho thời gian của bạn. Laravel (trong trường hợp của tôi) đang sử dụng một số bộ phận của Symfony nếu tôi không nhầm, vì vậy bạn hoàn toàn đúng khi không phát minh lại bánh xe. Tôi đã bắt đầu câu hỏi này (và tiền thưởng) để hiểu thêm về cách người khác thực hiện các bản dịch, tôi bắt đầu tin rằng có rất nhiều thực tiễn tốt nhất hiện có :-)
Joshua - Pendo

1

Tôi đã tự hỏi mình những câu hỏi liên quan hết lần này đến lần khác, rồi bị lạc trong các ngôn ngữ chính thức ... nhưng chỉ để giúp bạn hiểu một chút tôi muốn chia sẻ một số phát hiện:

Tôi khuyên bạn nên xem qua CMS nâng cao

Typo3cho PHP (tôi biết có rất nhiều thứ nhưng đó là thứ tôi nghĩ là chín chắn nhất)

Plone trong Python

Nếu bạn phát hiện ra rằng web năm 2013 sẽ hoạt động khác đi, hãy bắt đầu lại từ đầu. Điều đó có nghĩa là tập hợp một đội ngũ những người có kỹ năng / kinh nghiệm cao để xây dựng một CMS mới. Có thể bạn muốn đưa ra một cái nhìn về polymer cho mục đích đó.

Nếu nói đến mã hóa và các trang web đa ngôn ngữ / hỗ trợ ngôn ngữ bản địa, tôi nghĩ mọi lập trình viên nên có một đầu mối về unicode. Nếu bạn không biết unicode, chắc chắn bạn sẽ làm xáo trộn dữ liệu của mình. Đừng đi với hàng ngàn mã ISO. Họ sẽ chỉ tiết kiệm cho bạn một số bộ nhớ. Nhưng bạn có thể làm mọi thứ theo nghĩa đen với UTF-8 thậm chí lưu trữ các ký tự Trung Quốc. Nhưng để làm được điều đó, bạn cần lưu trữ ký tự 2 hoặc 4 byte để biến nó thành utf-16 hoặc utf-32.

Nếu đó là về mã hóa URL, một lần nữa ở đó bạn không nên trộn mã hóa và lưu ý rằng ít nhất đối với tên miền có các quy tắc được xác định bởi các hành lang khác nhau cung cấp các ứng dụng như trình duyệt. ví dụ: một tên miền có thể rất giống như:

üankofamerica.com hoặc bankofamerica.com samesamebutdifferent;)

Tất nhiên bạn cần hệ thống tập tin để làm việc với tất cả các bảng mã. Một điểm cộng nữa cho unicode sử dụng hệ thống tập tin utf-8.

Nếu đó là về bản dịch, hãy nghĩ về cấu trúc của tài liệu. ví dụ một cuốn sách hoặc một bài báo. Bạn có các docbookthông số kỹ thuật để hiểu về các cấu trúc. Nhưng trong HTML, nó chỉ là về các khối nội dung. Vì vậy, bạn muốn có một bản dịch ở cấp độ đó, cũng ở cấp độ trang web hoặc cấp độ tên miền. Vì vậy, nếu một khối không tồn tại thì nó không tồn tại, nếu một trang web không tồn tại, bạn sẽ được chuyển hướng đến cấp điều hướng phía trên. Nếu một tên miền phải hoàn toàn khác nhau trong cấu trúc điều hướng, thì .. đó là một cấu trúc hoàn toàn khác để quản lý. Điều này đã có thể được thực hiện với Typo3.

Nếu đó là về các khung công tác, những thứ trưởng thành nhất mà tôi biết, để thực hiện các công cụ chung như MVC (từ thông dụng tôi thực sự ghét nó! Giống như "hiệu suất" Nếu bạn muốn bán một cái gì đó, hãy sử dụng từ hiệu suất và featurich và bạn bán ... những gì địa ngục) là Zend. Nó đã được chứng minh là một điều tốt để mang lại các tiêu chuẩn cho các lập trình viên hỗn loạn php. Nhưng, typo3 cũng có một Framework bên cạnh CMS. Gần đây, nó đã được phát triển lại và được gọi là Flow3. Các khung của khóa học bao gồm sự trừu tượng hóa cơ sở dữ liệu, khuôn mẫu và các khái niệm cho bộ nhớ đệm, nhưng có các điểm mạnh riêng.

Nếu đó là về bộ nhớ đệm ... điều đó có thể cực kỳ phức tạp / nhiều lớp. Trong PHP, bạn sẽ nghĩ về accellerator, opcode, mà còn cả html, httpd, mysql, xml, css, js ... bất kỳ loại cache nào. Tất nhiên một số phần nên được lưu trữ và các phần động như câu trả lời trên blog không nên. Một số nên được yêu cầu qua AJAX với các url được tạo. JSON, hashbang, v.v.

Sau đó, bạn muốn có bất kỳ thành phần nhỏ nào trên trang web của mình chỉ được truy cập hoặc quản lý bởi một số người dùng nhất định , vì vậy về mặt khái niệm có vai trò lớn.

Ngoài ra, bạn muốn thống kê , có thể đã phân phối hệ thống / facebook của facebook, v.v ... bất kỳ phần mềm nào sẽ được xây dựng trên đầu của bạn trên các cm hàng đầu ... vì vậy bạn cần các loại cơ sở dữ liệu khác nhau , bigdata, xml, bất cứ điều gì .

tốt, tôi nghĩ rằng điều đó là đủ cho bây giờ. Nếu bạn chưa từng nghe về typo3 / plone hoặc các khung được đề cập, bạn có đủ để nghiên cứu. Trên con đường đó, bạn sẽ tìm thấy rất nhiều giải pháp cho những câu hỏi bạn chưa hỏi.

Nếu sau đó bạn nghĩ, hãy tạo một CMS mới vì năm 2013 và php sắp chết, thì bạn có thể tham gia bất kỳ nhóm nhà phát triển nào khác với hy vọng không bị mất.

Chúc may mắn!

Và btw. Làm thế nào về mọi người sẽ không có bất kỳ trang web nữa trong tương lai? và tất cả chúng ta sẽ có trên google +? Tôi hy vọng các nhà phát triển trở nên sáng tạo hơn một chút và làm điều gì đó hữu ích (để không bị đồng hóa bởi borgle)

//// Chỉnh sửa /// Chỉ cần suy nghĩ một chút cho ứng dụng hiện có của bạn:

Nếu bạn có một CMS mysql php và bạn muốn nhúng hỗ trợ multilang. bạn có thể sử dụng bảng của mình với một cột quảng cáo cho bất kỳ ngôn ngữ nào hoặc chèn bản dịch với id đối tượng và id ngôn ngữ trong cùng một bảng hoặc tạo một bảng giống hệt nhau cho bất kỳ ngôn ngữ nào và chèn các đối tượng vào đó, sau đó tạo liên kết chọn nếu bạn muốn để có tất cả chúng được hiển thị. Đối với cơ sở dữ liệu, hãy sử dụng utf8 chung ci và tất nhiên trong phần trước / phụ trợ sử dụng văn bản / mã hóa utf8. Tôi đã sử dụng các phân đoạn đường dẫn url cho các url theo cách bạn đã giải thích như

domain.org/en/about bạn có thể ánh xạ ID lang vào bảng nội dung của mình. dù sao bạn cũng cần phải có một bản đồ các tham số cho các url của mình, vì vậy bạn muốn xác định một tham số sẽ được ánh xạ từ một đường dẫn trong URL của bạn, ví dụ như

domain.org/en/about/empologists/IT/adologists/

cấu hình tra cứu

pageid | url

1 | /about/emp NHÂN / .. / ..

1 | /../about/emp NHÂN../../

ánh xạ các tham số vào đường dẫn url ""

$parameterlist[lang] = array(0=>"nl",1=>"en"); // default nl if 0
$parameterlist[branch] = array(1=>"IT",2=>"DESIGN"); // default nl if 0
$parameterlist[employertype] = array(1=>"admin",1=>"engineer"); //could be a sql result 

$websiteconfig[]=$userwhatever;
$websiteconfig[]=$parameterlist;
$someparameterlist[] = array("branch"=>$someid);
$someparameterlist[] = array("employertype"=>$someid);
function getURL($someparameterlist){ 
// todo foreach someparameter lookup pathsegment 
return path;
}

mỗi lần nói, điều đó đã được đề cập ở bài trên.

Và để không quên, bạn cần "viết lại" url vào tệp php đang tạo trong hầu hết các trường hợp là index.php


Cảm ơn vì nhận xét, chắc chắn có những điều tôi nên suy nghĩ. Tôi đã sử dụng mã hóa utf8 được vài năm rồi, tôi đã từng phải vật lộn với nhân vật một lần ;-) Mặt khác, loại CMS / Framework có nghĩa là không có yếu tố nào trong câu trả lời của bạn khi tôi đang tìm kiếm phương pháp độc lập nền tảng như thể chúng ta đang mã hóa từ đầu.
Joshua - Pendo

nếu bạn thực sự muốn viết mã từ đầu, tôi khuyên bạn nên xem xét về Dartlang và polymer. Vì dartlang đang làm việc trong trình duyệt và có hỗ trợ 32 và 64 bit và có thể được sử dụng cho hầu hết các mục đích trên máy chủ và có trình biên dịch dart2js thực sự đáng để nghiên cứu. Nếu mọi người nói về sự độc lập nền tảng, họ nghĩ về java ... chúng tôi biết điều đó có nghĩa là gì. Build Process ... Tôi nghĩ rằng tôi sẽ sử dụng JSON để trao đổi. tạo trang web khách hàng với hashbang và máy chủ .. cũng làm bất cứ điều gì bạn muốn để đảm bảo sự hợp tác.
Bác sĩ Dama

Dataabaselayout và logic logic là nhiệm vụ chính. Không ai sẽ làm điều đó ở đây cho bạn ... nhưng chính Ý tưởng mới là điều đáng quan tâm. Vì tôi không quan tâm đến hành lang nhưng để hoàn thành công việc, tôi hy vọng bạn có thể tạo mô hình và chia sẻ một số nội dung. Tôi đang làm việc trên các nhiệm vụ tương tự ngay bây giờ. Nhưng tôi vẫn đang lên kế hoạch. Tôi đang xem Typo3 như một phụ trợ và tạo cấu trúc máy khách mới. Mẫu đa ngôn ngữ được giải quyết trong phần phụ trợ và sẽ chia sẻ thông tin theo cách dành riêng cho các công cụ tìm kiếm / dịch vụ web. Dù sao, tất cả các bối cảnh và nhiệm vụ xây dựng liên tục của nó
Tiến sĩ Dama

-1

Cơ sở dữ liệu làm việc:

Tạo bảng ngôn ngữ 'ngôn ngữ':

Lĩnh vực:

language_id(primary and auto increamented)

language_name

created_at

created_by

updated_at

updated_by

Tạo một bảng trong cơ sở dữ liệu 'nội dung':

Lĩnh vực:

content_id(primary and auto incremented)

main_content

header_content

footer_content

leftsidebar_content

rightsidebar_content

language_id(foreign key: referenced to languages table)

created_at

created_by

updated_at

updated_by

Công việc kết thúc:

Khi người dùng chọn bất kỳ ngôn ngữ nào từ danh sách thả xuống hoặc bất kỳ khu vực nào, sau đó lưu id ngôn ngữ đã chọn trong phiên như,

$_SESSION['language']=1;

Bây giờ hãy tìm nạp dữ liệu từ bảng nội dung 'nội dung' dựa trên id ngôn ngữ được lưu trữ trong phiên.

Chi tiết có thể tìm thấy ở đây http://skillrow.com/multallel-website-in-php-2/


1
Đây là một cách để tích hợp ngôn ngữ đơn giản sau đó cần thiết, bạn thậm chí đã cố gắng đọc các bài viết đầy đủ và đưa ra câu trả lời?
Joshua - Pendo

-2

Là một người sống ở Quebec, nơi hầu hết tất cả các trang web là tiếng Pháp và tiếng Anh ... tôi đã thử rất nhiều nếu không phải hầu hết các plugin đa ngôn ngữ cho WP ... một giải pháp hữu ích duy nhất hoạt động với tất cả các trang web của tôi là mQtranslate ... tôi sống và chết với nó

https://wordpress.org/plugins/mqtransTable/


1
vâng, WP không phải là bất kỳ yếu tố nào của câu hỏi. Đây có thể là một lời nhận xét aswel
Joshua - Pendo

-3

Thế còn WORDPRESS + MULTI-LANGUAGE SITE BASIS(plugin) thì sao? trang web sẽ có cấu trúc:

  • example.com/ eng / category1 / ....
  • example.com/ eng / my-page ....
  • example.com/ rus / loại1 / ....
  • example.com/ rus / trang của tôi ....

Plugin cung cấp Giao diện cho Dịch tất cả các cụm từ, với logic đơn giản:

(ENG) my_title - "Hello user"
(SPA) my_title - "Holla usuario"

sau đó nó có thể được xuất ra:
echo translate('my_title', LNG); // LNG is auto-detected

Tuy nhiên, hãy kiểm tra xem plugin có còn hoạt động không.


3
và không phải là "Holla userio" trong tiếng Tây Ban Nha là "Hola Usuario"
bheatcoker

1
Lol Holla userio, thật buồn cười!
spekdrum

vì lý do tôi không biết tiếng Tây Ban Nha (chỉ sử dụng ví dụ), hãy nhanh chân xuống downvote !! :)
T.Todua

-5

Một tùy chọn thực sự đơn giản hoạt động với bất kỳ trang web nào bạn có thể tải lên Javascript là www.multallelizer.com

Nó cho phép bạn đặt tất cả văn bản cho tất cả các ngôn ngữ lên một trang và sau đó ẩn các ngôn ngữ mà người dùng không cần phải xem. Hoạt động tốt.


Coi chừng, SEO sẽ rất tệ! Thêm vào đó bạn tải tất cả nội dung trong khi bạn chỉ cần một phần của nó là thực tế xấu.
Hafenkranich

những thứ kỳ lạ mà trang web chỉ bằng tiếng Anh ... tại sao họ không sử dụng giải pháp của họ ??
eduardo.lopes
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.