2010-06-03 93 views
8

2009年4月26日發佈的「On the state of i18n in Perl」博文建議使用libintl-perl發行版中的Locale::TextDomain模塊來處理Perl中的l10n/i18n。除此之外,我必須使用gettext,並且Locale :: Messages/Locale :: TextDomain中的gettext支持比在Locale::Maketext中的gettext模擬更自然。在Perl中使用gettext和Locale :: TextDomain進行本地化,如果Locale :: TextDomain不可用

在GNU的gettext手冊第四章 「15 Other Programming Languages」 小標題 「15.5.18 Perl」 說:

便攜

libintl-perl包是平臺無關的,但不是Perl的核心的一部分。如果程序包未安裝在目標系統上,則程序員負責提供所需功能的虛擬實現。

然而,如果包被安裝在目標既不在gettext的源examples/hello-perl兩個例子(一個使用較低水平區域設置::消息,一個使用更高級別的區域設置:: TextDomain)包括檢測系統,如果不是,則提供虛擬執行

什麼是複雜物質(相對於當安裝或不包檢測)是區域設置的下列片段:: TextDomain手冊頁:

概要

use Locale::TextDomain ('my-package', @locale_dirs); 

use Locale::TextDomain qw (my-package); 

USAGE

請務必記住,您使用Locale :: TextDomain(3)部分「SYNOPSIS」,這意味着你必須使用它,而不是要求它。該模塊的行爲與其他模塊相比完全不同。

請問如何檢測libintl-perl是否存在於目標系統上,以及如何在未安裝的情況下提供虛擬貫穿實現?或者給出這樣做的程序/模塊的例子?

回答

7

gettext手冊錯誤地表明它不適合您demand a CPAN prerequisite。每個人都在Perl世界中這樣做,並且感謝CPAN基礎架構和工具鏈,它工作得很好。在最壞的情況下,您可以捆綁您需要的依賴關係。

直回答你的問題是:

use Try::Tiny; 
try { 
    require Locale::TextDomain; 
    Locale::TextDomain->import('my-package', @locale_dirs); 
} catch { 
    warn 'Soft dependency could not be loaded, using fallback.'; 
    require inc::Local::Dummy::Locale::TextDomain; 
} 

說明:use is just require at compile time followed by import,這是可以接受的它,以迫使這在運行時執行分裂。

4

你必須包括地點:: TextDomain利用的需要,而不是因爲它的目的正是這種情況下,當你想對Perl,不顯眼的國際化時,一切都需要國際化你的Perl代碼來交換:

print "Hello world!\n"; 

與此:

use Locale::TextDomain qw (com.example.myapp); 

print __"Hello world!\n"; 

在像C語言預處理這是比較容易實現。關於所有國際化的C庫包含#define這樣的:

#define _(s) dgettext (GETTEXT_PACKAGE, s) 

這意味着,_("Hello world!\n")擴展到包含包的textdomain函數調用。 Perl源代碼不能進行可移植的預處理,因此Locale::TextDomain爲此目的「濫用」使用編譯指示的導入機制,以便它可以將.pm文件與特定的.mo文件相關聯。 textdomain是您的程序包安裝的.mo文件的文件名。

如果您不喜歡這種方法,請不要使用它。您也可以讓沒有它:

require Locale::Messages; 
print Locale::Messages::dgettext ("com.example.myapp", "Hello world!\n"); 

然而,Locale::TextDomain很受歡迎,因爲它同樣在一個更突兀的方式。

關於取決於非核心爲Perl庫:

無論Perl模塊屬於Perl的核心或不依賴於Perl版本。每個用戶都可以在Perl或Perl附帶的Perl模塊上安裝不同版本的Perl核心模塊。因此,一個健壯的軟件包配置將總是檢查Perl庫的所需版本,就像它將檢查任何其他庫的所需版本一樣。假設檢查perl和。是一樣的。檢查某個特定版本的Perl模塊是否存在是一個麻煩。

BTW,Try::Tiny也不是Perl核心的一部分。也許不是使用它來檢查其他Perl模塊的最佳選擇。當你想測試libintl-perl時,只需在配置腳本中執行perl -MLocale::TextDomain -e exit並檢查退出狀態。

2

根據daxim的回答,這裏有一個可能的實現。它檢測Locale :: TextDomain是否可用,併爲__和__x函數提供簡單的無操作回退。我會很感激這個代碼的改進和建議。

BEGIN 
{ 
    if (eval("require Locale::TextDomain; 1;")) 
    { 
     Locale::TextDomain->import('my-package', @locale_dirs); 
    } 
    else 
    { 
     my $subCode = <<'EOF' 

     sub __ 
     { 
      return $_[0]; 
     } 

     sub __x 
     { 
      my $s = shift; 
      my %args = @_; 
      $s =~ s/\{(\w+)\}/$args{$1}/sg; 
      return $s; 
     } 
EOF 
; 
     eval($subCode); 
    } 
} 

我認爲整個代碼需要住在BEGIN裏面,否則代碼中的__和__x調用會導致錯誤。此外,使用eval()創建回退函數以避免「原型不匹配:」警告。我會對更優雅的解決方案感興趣。對於後一點。

+0

也許** Package :: Stash **或直接操作符號表而不是文本評估。 – 2013-04-25 15:16:49

1

創建一個目錄「回退/區域設置」,並有創建模塊TextDomain.pm與存根實現的,你需要的所有功能:

package Locale::TextDomain; 

use strict; 

sub __($) { return $_[0] } 
sub __n($$$) { return $_[2] == 1 ? $_[0] : $_[1] } 

# And so on, see the source of Locale::TextDomain for getting an 
# idea how to implement the other stubs. 

現在,插入一個BEGIN塊到應用程序的入口點(這通常是一個.pl腳本,而不是一個。PM模塊):

BEGIN { 
    push @INC, "fallback"; 
} 

現在Perl將總是查找地區/ TextDomain.pm在@INC,懷疑在回退目錄中的存根實現。

相關問題