override gettext .mo files
Asked Answered
P

4

6

For translations in our application, we're using Zend Translate with the gettext adapter. In each module is a folder translations, containing .mo files for all the languages;

  • da.mo
  • nl.mo
  • en.mo

Which are scanned and added through the addTranslation() method:

if ( is_dir( $translations_dir ) ) {
    foreach ( new DirectoryIterator( $translations_dir ) as $file ) {
        if ( substr( $file, -3 ) == '.mo' ) {
            $ZendTranslate->addTranslation( $file->getPathname(), $file->getBasename('.mo') );
        }
    }
}

The strings in my application are translated using the _() method, passing the current language as a parameter (it's stored in my framework's Language class):

$ZendTranslate->_( $string, $this->language );

Now I need to customize the Dutch (nl) language strings for a specific customer. I don't want to modify the nl.mo file, as that would affect other customers. So I created a file called nl_kpn.mo (kpn is the customer name), and switched the $this->language to 'nl_kpn'. I was hoping Zend Transate would take nl.mo as the base file, overriding the customized strings found in nl_kpn.mo. But unfortunately I experienced, as the manual states:

fr_CH will be downgraded to fr

So all the strings were still from the nl.mo file, even though $this->language was set to 'nl_kpn'. So how can I create a more specific version of a language, overriding strings from the general one? It must be possible, right? Because there's also en_UK and en_US, which are different 'dialects' of the same language.

Parboil answered 31/8, 2011 at 7:45 Comment(1)
Hmm, what class your addTranslation() method belongs to? I found only public function addTranslation($options = array()) in Zend_Translate_Adapter class, but it has another signature as you can see.Scarcely
E
0

As Rijk said, Zend_Translate will try to invoke a Zend_Locale, which simply does not exist. Unfortunatly, the listing has been set to private, so we may not use inheritance to simply derive our own implementation.

However, you have two options. Depending on your setup, you may just set your own nl.mo-file for this specific customer by providing a different directory in the configuration. That way, you may link all other language-files and have a separate one for the kpn-client.

The second option you have is to get rid of Zend_Translate and use the default php gettext. As you are already using gettext-files and seem to use the translate()-function, you would not have any more work than to refactor $ZendTranslate to your gettext-class. If you do use Zend_Translate automatically in other classes (e.g. in Zend_Navigation), you can just leave those intact.

While the 2nd option does work, it is a bit messy - however, the third and clean alternative is to inherit Zend_Locale and rewriting all methods accessing the private language list. That way, you can add your own. Or you even go the lenghts of rewriting the parts of Zend_Locale to support dynamical adding of languages and send a patch file in - that way, we may benefit from your work, too. ;)

Embrocation answered 19/9, 2011 at 20:27 Comment(1)
Thanks, good idea! Both options sound good, I hadn't even considered getting rid of Zend_Translate. In the real application we use our own framework which just adapts the Zend class, so it would require little to none code changes to change that. :)Parboil
P
1

I think the answer is just this is not possible. The locale has to be an existing language/dialect, and is validated with the list in Zend_Locale:

'root'  => true, 'aa_DJ' => true, 'aa_ER' => true, 'aa_ET' => true, 'aa'    => true,
'af_NA' => true, 'af_ZA' => true, 'af'    => true, 'ak_GH' => true, 'ak'    => true,
'am_ET' => true, 'am'    => true, 'ar_AE' => true, 'ar_BH' => true, 'ar_DZ' => true,
'ar_EG' => true, 'ar_IQ' => true, 'ar_JO' => true, 'ar_KW' => true, 'ar_LB' => true,
'ar_LY' => true, 'ar_MA' => true, 'ar_OM' => true, 'ar_QA' => true, 'ar_SA' => true,
'ar_SD' => true, 'ar_SY' => true, 'ar_TN' => true, 'ar_YE' => true, 'ar'    => true,
'as_IN' => true, 'as'    => true, 'az_AZ' => true, 'az'    => true, 'be_BY' => true,
'be'    => true, 'bg_BG' => true, 'bg'    => true, 'bn_BD' => true, 'bn_IN' => true,
'bn'    => true, 'bo_CN' => true, 'bo_IN' => true, 'bo'    => true, 'bs_BA' => true,
'bs'    => true, 'byn_ER'=> true, 'byn'   => true, 'ca_ES' => true, 'ca'    => true,
'cch_NG'=> true, 'cch'   => true, 'cop'   => true, 'cs_CZ' => true, 'cs'    => true,
'cy_GB' => true, 'cy'    => true, 'da_DK' => true, 'da'    => true, 'de_AT' => true,
'de_BE' => true, 'de_CH' => true, 'de_DE' => true, 'de_LI' => true, 'de_LU' => true,
'de'    => true, 'dv_MV' => true, 'dv'    => true, 'dz_BT' => true, 'dz'    => true,
'ee_GH' => true, 'ee_TG' => true, 'ee'    => true, 'el_CY' => true, 'el_GR' => true,
'el'    => true, 'en_AS' => true, 'en_AU' => true, 'en_BE' => true, 'en_BW' => true,
'en_BZ' => true, 'en_CA' => true, 'en_GB' => true, 'en_GU' => true, 'en_HK' => true,
'en_IE' => true, 'en_IN' => true, 'en_JM' => true, 'en_MH' => true, 'en_MP' => true,
'en_MT' => true, 'en_NA' => true, 'en_NZ' => true, 'en_PH' => true, 'en_PK' => true,
'en_SG' => true, 'en_TT' => true, 'en_UM' => true, 'en_US' => true, 'en_VI' => true,
'en_ZA' => true, 'en_ZW' => true, 'en'    => true, 'eo'    => true, 'es_AR' => true,
'es_BO' => true, 'es_CL' => true, 'es_CO' => true, 'es_CR' => true, 'es_DO' => true,
'es_EC' => true, 'es_ES' => true, 'es_GT' => true, 'es_HN' => true, 'es_MX' => true,
'es_NI' => true, 'es_PA' => true, 'es_PE' => true, 'es_PR' => true, 'es_PY' => true,
'es_SV' => true, 'es_US' => true, 'es_UY' => true, 'es_VE' => true, 'es'    => true,
'et_EE' => true, 'et'    => true, 'eu_ES' => true, 'eu'    => true, 'fa_AF' => true,
'fa_IR' => true, 'fa'    => true, 'fi_FI' => true, 'fi'    => true, 'fil_PH'=> true,
'fil'   => true, 'fo_FO' => true, 'fo'    => true, 'fr_BE' => true, 'fr_CA' => true,
'fr_CH' => true, 'fr_FR' => true, 'fr_LU' => true, 'fr_MC' => true, 'fr_SN' => true,
'fr'    => true, 'fur_IT'=> true, 'fur'   => true, 'ga_IE' => true, 'ga'    => true,
'gaa_GH'=> true, 'gaa'   => true, 'gez_ER'=> true, 'gez_ET'=> true, 'gez'   => true,
'gl_ES' => true, 'gl'    => true, 'gsw_CH'=> true, 'gsw'   => true, 'gu_IN' => true,
'gu'    => true, 'gv_GB' => true, 'gv'    => true, 'ha_GH' => true, 'ha_NE' => true,
'ha_NG' => true, 'ha_SD' => true, 'ha'    => true, 'haw_US'=> true, 'haw'   => true,
'he_IL' => true, 'he'    => true, 'hi_IN' => true, 'hi'    => true, 'hr_HR' => true,
'hr'    => true, 'hu_HU' => true, 'hu'    => true, 'hy_AM' => true, 'hy'    => true,
'ia'    => true, 'id_ID' => true, 'id'    => true, 'ig_NG' => true, 'ig'    => true,
'ii_CN' => true, 'ii'    => true, 'in'    => true, 'is_IS' => true, 'is'    => true,
'it_CH' => true, 'it_IT' => true, 'it'    => true, 'iu'    => true, 'iw'    => true,
'ja_JP' => true, 'ja'    => true, 'ka_GE' => true, 'ka'    => true, 'kaj_NG'=> true,
'kaj'   => true, 'kam_KE'=> true, 'kam'   => true, 'kcg_NG'=> true, 'kcg'   => true,
'kfo_CI'=> true, 'kfo'   => true, 'kk_KZ' => true, 'kk'    => true, 'kl_GL' => true,
'kl'    => true, 'km_KH' => true, 'km'    => true, 'kn_IN' => true, 'kn'    => true,
'ko_KR' => true, 'ko'    => true, 'kok_IN'=> true, 'kok'   => true, 'kpe_GN'=> true,
'kpe_LR'=> true, 'kpe'   => true, 'ku_IQ' => true, 'ku_IR' => true, 'ku_SY' => true,
'ku_TR' => true, 'ku'    => true, 'kw_GB' => true, 'kw'    => true, 'ky_KG' => true,
'ky'    => true, 'ln_CD' => true, 'ln_CG' => true, 'ln'    => true, 'lo_LA' => true,
'lo'    => true, 'lt_LT' => true, 'lt'    => true, 'lv_LV' => true, 'lv'    => true,
'mk_MK' => true, 'mk'    => true, 'ml_IN' => true, 'ml'    => true, 'mn_CN' => true,
'mn_MN' => true, 'mn'    => true, 'mo'    => true, 'mr_IN' => true, 'mr'    => true,
'ms_BN' => true, 'ms_MY' => true, 'ms'    => true, 'mt_MT' => true, 'mt'    => true,
'my_MM' => true, 'my'    => true, 'nb_NO' => true, 'nb'    => true, 'nds_DE'=> true,
'nds'   => true, 'ne_IN' => true, 'ne_NP' => true, 'ne'    => true, 'nl_BE' => true,
'nl_NL' => true, 'nl'    => true, 'nn_NO' => true, 'nn'    => true, 'no'    => true,
'nr_ZA' => true, 'nr'    => true, 'nso_ZA'=> true, 'nso'   => true, 'ny_MW' => true,
'ny'    => true, 'oc_FR' => true, 'oc'    => true, 'om_ET' => true, 'om_KE' => true,
'om'    => true, 'or_IN' => true, 'or'    => true, 'pa_IN' => true, 'pa_PK' => true,
'pa'    => true, 'pl_PL' => true, 'pl'    => true, 'ps_AF' => true, 'ps'    => true,
'pt_BR' => true, 'pt_PT' => true, 'pt'    => true, 'ro_MD' => true, 'ro_RO' => true,
'ro'    => true, 'ru_RU' => true, 'ru_UA' => true, 'ru'    => true, 'rw_RW' => true,
'rw'    => true, 'sa_IN' => true, 'sa'    => true, 'se_FI' => true, 'se_NO' => true,
'se'    => true, 'sh_BA' => true, 'sh_CS' => true, 'sh_YU' => true, 'sh'    => true,
'si_LK' => true, 'si'    => true, 'sid_ET'=> true, 'sid'   => true, 'sk_SK' => true,
'sk'    => true, 'sl_SI' => true, 'sl'    => true, 'so_DJ' => true, 'so_ET' => true,
'so_KE' => true, 'so_SO' => true, 'so'    => true, 'sq_AL' => true, 'sq'    => true,
'sr_BA' => true, 'sr_CS' => true, 'sr_ME' => true, 'sr_RS' => true, 'sr_YU' => true,
'sr'    => true, 'ss_SZ' => true, 'ss_ZA' => true, 'ss'    => true, 'st_LS' => true,
'st_ZA' => true, 'st'    => true, 'sv_FI' => true, 'sv_SE' => true, 'sv'    => true,
'sw_KE' => true, 'sw_TZ' => true, 'sw'    => true, 'syr_SY'=> true, 'syr'   => true,
'ta_IN' => true, 'ta'    => true, 'te_IN' => true, 'te'    => true, 'tg_TJ' => true,
'tg'    => true, 'th_TH' => true, 'th'    => true, 'ti_ER' => true, 'ti_ET' => true,
'ti'    => true, 'tig_ER'=> true, 'tig'   => true, 'tl'    => true, 'tn_ZA' => true,
'tn'    => true, 'to_TO' => true, 'to'    => true, 'tr_TR' => true, 'tr'    => true,
'trv_TW'=> true, 'trv'   => true, 'ts_ZA' => true, 'ts'    => true, 'tt_RU' => true,
'tt'    => true, 'ug_CN' => true, 'ug'    => true, 'uk_UA' => true, 'uk'    => true,
'ur_IN' => true, 'ur_PK' => true, 'ur'    => true, 'uz_AF' => true, 'uz_UZ' => true,
'uz'    => true, 've_ZA' => true, 've'    => true, 'vi_VN' => true, 'vi'    => true,
'wal_ET'=> true, 'wal'   => true, 'wo_SN' => true, 'wo'    => true, 'xh_ZA' => true,
'xh'    => true, 'yo_NG' => true, 'yo'    => true, 'zh_CN' => true, 'zh_HK' => true,
'zh_MO' => true, 'zh_SG' => true, 'zh_TW' => true, 'zh'    => true, 'zu_ZA' => true,
'zu'    => true

I guess I'll just have to devise a different way to override the files. Maybe just loading in a different .po file from PHP.

Parboil answered 15/9, 2011 at 14:16 Comment(0)
D
0

you can try to override _() method from Zend_Translate_Adapter and check file name :

public function _($messageId, $locale = null)
{
     if ($locale !== null && strpos($locale, "_") !== false && $this->translate($messageId, $locale) === $messageId)
     {
          $languages = explode("_", $locale);
          $locale = $languages[0];
     }

     return $this->translate($messageId, $locale);
}
Desmund answered 13/9, 2011 at 12:46 Comment(1)
I don't understand how this could help? I want the class to return the strings from nl_kpn, not 'downgrade' to nl (this is already happening).Parboil
S
0

I think that the best way to do this is using the isTranslated method. You can do

if ($translate->isTranslated('message1')) {
    print "'message1' can be translated";
}

if (!($translate->isTranslated('message1', true, 'de'))) {
    print "'message1' can not be translated to 'de'"
    . " as it's available only in 'de_AT'";
}

if ($translate->isTranslated('message1', false, 'de')) {
    print "'message1' can be translated in 'de_AT' as it falls back to 'de'";
}


isTranslated ($messageId, $original = false, $locale = null)
takes the text you want to check as its first parameter, and as optional third parameter the locale for which you want to do the check. The optional second parameter declares whether translation is fixed to the declared language or a lower set of translations can be used. If you have a text which can be returned for 'en' but not for 'en_US' you will normally get the translation returned, but by setting $original to true, isTranslated() will return false.
Does this works for you?

Standley answered 13/9, 2011 at 14:17 Comment(1)
I'm not sure you understand my question.. I want to add 'custom' languages like nl_[CUSTOMER].po, and then override some strings of the original nl.po file and 'inherit' the others.Parboil
E
0

As Rijk said, Zend_Translate will try to invoke a Zend_Locale, which simply does not exist. Unfortunatly, the listing has been set to private, so we may not use inheritance to simply derive our own implementation.

However, you have two options. Depending on your setup, you may just set your own nl.mo-file for this specific customer by providing a different directory in the configuration. That way, you may link all other language-files and have a separate one for the kpn-client.

The second option you have is to get rid of Zend_Translate and use the default php gettext. As you are already using gettext-files and seem to use the translate()-function, you would not have any more work than to refactor $ZendTranslate to your gettext-class. If you do use Zend_Translate automatically in other classes (e.g. in Zend_Navigation), you can just leave those intact.

While the 2nd option does work, it is a bit messy - however, the third and clean alternative is to inherit Zend_Locale and rewriting all methods accessing the private language list. That way, you can add your own. Or you even go the lenghts of rewriting the parts of Zend_Locale to support dynamical adding of languages and send a patch file in - that way, we may benefit from your work, too. ;)

Embrocation answered 19/9, 2011 at 20:27 Comment(1)
Thanks, good idea! Both options sound good, I hadn't even considered getting rid of Zend_Translate. In the real application we use our own framework which just adapts the Zend class, so it would require little to none code changes to change that. :)Parboil

© 2022 - 2024 — McMap. All rights reserved.