Asked  7 Months ago    Answers:  5   Viewed   113 times

This is a little code snippet from php manual:

putenv('LC_ALL=zh_CN');
setlocale(LC_ALL, 'zh_CN');

bindtextdomain('domain', './locale');
textdomain('domain');

echo gettext('Hello');

Which will output ?? as defined in domain.mo file, but the problem is as long as the Apache is running, gettext() always return the cached result.

If I change the translation of Hello to ?? in domain.mo, it will still output ??.

However there is a fix for this by changing the domain argument of bindtextdomain() and textdomain() to a new name. Like from "domain" to "domain2". But this is really painful to edit the php file every time I updated the .mo file.

Is there a better way for doing this, like remove some folders or calling some php functions to do the job? So that I can write a little script for this purpose.

 Answers

38

Every solution (1, 2, 3) suggests changing the domain to get rid of the cache problem, but this will create lots of out-of-date cache in memory.

So I dug into the gnu-gettext source for details on the cache strategy (bindtextdom.c:78.)

When bindtextdomain(domain, dirname) is called, it will check whether domain exists in the cache; if so, it will then check if dirname is the same with the one in the cache. If this fails, it will force a cache flush for the same domain, instead of creating a new one in memory.

The fix is incredibly simple, first create a dummy link to the locale folder where your .mo file is stored:

cd locale
ln -s . nocache

Then add one single line before bindtextdomain()

bindtextdomain('domain', './locale/nocache');
bindtextdomain('domain', './locale');

Now the cache is forced to flush every time.


Updates:

This hack may not works in some cases (Can't figure out the exact conditions.) This solution is NOT something you should use in production environment, but only for those who need to fix something while keeping httpd running!

Whenever you can, please avoid using gettext from very beginning, this is really something ancient and should be deprecated for good.

Wednesday, March 31, 2021
 
Saxophlutist
answered 7 Months ago
33

As far as I can see in the manual, it is not possible to call functions inside HEREDOC strings. A cumbersome way would be to prepare the words beforehand:

<?php

    $world = _("World");

    $str = <<<EOF
    <p>Hello</p>
    <p>$world</p>
EOF;
    echo $str;
?>

a workaround idea that comes to mind is building a class with a magic getter method.

You would declare a class like this:

class Translator
{
 public function __get($name) {
  return _($name); // Does the gettext lookup
  }
 }

Initialize an object of the class at some point:

  $translate = new Translator();

You can then use the following syntax to do a gettext lookup inside a HEREDOC block:

    $str = <<<EOF
    <p>Hello</p>
    <p>{$translate->World}</p>
EOF;
    echo $str;
?>

$translate->World will automatically be translated to the gettext lookup thanks to the magic getter method.

To use this method for words with spaces or special characters (e.g. a gettext entry named Hello World!!!!!!, you will have to use the following notation:

 $translate->{"Hello World!!!!!!"}

This is all untested but should work.

Update: As @mario found out, it is possible to call functions from HEREDOC strings after all. I think using getters like this is a sleek solution, but using a direct function call may be easier. See the comments on how to do this.

Wednesday, March 31, 2021
 
RahulG
answered 7 Months ago
86

You just must not have string variables. You should do e.g.

$sentance = _('Hello world');

The other way is to use some king of parser, which will be able to find your hello world strings and finally output somewhere

$fakie = _('Hello World');

This output should be stored in some file, which will then be pickedup by poedit and translated. For showing the translation you can than use

$myTranslation = _($sentance);

We used this conversion process for javascript files and smarty templates.

Wednesday, March 31, 2021
 
mistero
answered 7 Months ago
79

If you want to refresh a specific object, then the Refresh() method may be your best bet.

Like this:

Context.Refresh(RefreshMode.OverwriteCurrentValues, objectToRefresh);

You can also pass an array of objects or an IEnumerable as the 2nd argument if you need to refresh more than one object at a time.

Update

I see what you're talking about in comments, in reflector you see this happening inside .Refresh():

object objectByKey = context.Services.GetObjectByKey(trackedObject.Type, keyValues);
if (objectByKey == null)
{
    throw Error.RefreshOfDeletedObject();
}

The method you linked seems to be your best option, the DataContext class doesn't provide any other way to clear a deleted row. The disposal checks and such are inside the ClearCache() method...it's really just checking for disposal and calling ResetServices() on the CommonDataServices underneath..the only ill-effect would be clearing any pending inserts, updates or deletes that you have queued.

There is one more option, can you fire up another DataContext for whatever operation you're doing? It wouldn't have any cache to it...but that does involve some computational cost, so if the pending insert, update and deletes aren't an issue, I'd stick with the ClearCache() approach.

Monday, August 9, 2021
 
Gaurav
answered 3 Months ago
53

This should do the trick:

Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)

 Dim path As String
 path="/AbosoluteVirtualPath/OutputCached.aspx"
 HttpResponse.RemoveOutputCacheItem(path)

End Sub
Thursday, August 12, 2021
 
khaverim
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :