User tests: Successful: Unsuccessful:
Dynamically add string for Dynamic strings
For example: COM_EXAMPLE_DYNAMICFIELD_LABEL
Adding ability to set custom strings on fly
Don't allow to force strings change/reset so one extension couldn't damage another
Add into isis/index.php
JFactory::getLanguage()->def('COM_NOTHING_TEST', 'It works!');
echo JText::_('COM_NOTHING_TEST');
and then visit any page in the back end. You should get:
May be added to documentation, but should be marked with:
Try to avoid use of this if possible; Language files implementation first attitude
Allows
JFactory::getLanguage()->def('MY_CONSTANT','My hard my_constant value');
...
echo JText::_('MY_CONSTANT');
instead of
echo (JText::_('MY_CONSTANT') && JText::_('MY_CONSTANT')!='MY_CONSTANT')?JText::_('MY_CONSTANT'):'My hard my_constant value';
Behavior switched off in debugging mode.
Status | New | ⇒ | Pending |
Category | ⇒ | Libraries |
Labels |
Added:
?
|
I have tested this item
@infograf768 for example you can take a look at this code
Here I'd like to use this for auto-generating entries for sidebar menu.
Or like this:
Table head generation based on $item`s fields
<thead>
<tr>
<th width="1%" class="nowrap center hidden-phone">
<?php echo JHTML::_('grid.sort', '<span class="icon-menu-2"></span>', 'ordering', $this->listDirn, false); ?>
</th>
<th width="1%" class="center">
<?php echo JHtml::_('grid.checkall'); ?>
</th>
<th width="1%" class="center">
</th>
<?php
foreach ($columns as $column){
?>
<th>
<?php echo JHTML::_('grid.sort', 'TABLE_LIST_HEAD_'.strtoupper($column), $column, $this->listDirn, $this->listOrder); ?>
</th>
<?php
}
?>
</tr>
</thead>
the thing with this code is: fields can be generated and added to form based on some DB data.
And based on new functionality of JLanguage we could add custom stings along with adding fields.
I have tested this item
Test OK
I don't get the point of this. You want to add strings where you take the value from the database (or from wherever you take it)? So you have to know the translated value to use this. Then why even go through JText when you already have the value? Doesn't make much sense to me.
Then why even go through JText when you already have the value?
It is useful, for the cases that you have no control on the code that calls the JText
Arguably one can override translations now without this new method, by ... creating a language file at runtime and loading it
I am pretty lost... could you explain what kind of precise value you expect for these made on the fly strings constants and how a user could translate these values when not knowing the constant as well as the value... the example above has hard coded value which can't be fetched by core language overrides. how would one manage when using multiple languages?
@infograf768
It's up to extension developer to guide users to how to translate things, which constants to use.
This is good thing to use in auto generated stuff, like library that I referenced to - it automates a lot of things and keep them flexible.
Example:
I have "custom" fields sub-extension [horizontal one - if say it in J!4 approach ] that allows users to create some custom fields that would be added to the forms and list views.
I set field name [given by user] to the constant, but guide users that they can change it by creating override for 'COM_CUSTFIELDS_FIELD_5_LABEL'.
Well in the end of the day: using this method is equal to
echo (JText::_('MY_CONSTANT') && JText::_('MY_CONSTANT')!='MY_CONSTANT')?JText::_('MY_CONSTANT'):'My hard my_constant value';
but more crispy and cool. Isn't it
JFactory::getLanguage()->addString('MY_CONSTANT','My hard my_constant value');
@dgt41 and @anibalsanchez - thanks for testing, appreciate that!
Personally I think you're better off with something like this:
echo JFactory::getLanguage()->hasKey('KEY') ? JText::_('KEY') : 'Hardcoded value';
Or put something into JText
that can support just spitting out a default if a key doesn't exist.
I see what it is you're aiming to accomplish, but I don't think adding strings to the catalogue at runtime in this manner is a good approach to it.
@mbabker using some thing like
JText::_('KEY','Default value')
will not be great.
Why would you use 'register new string' instead of approach that you're advising:
You'll be forced to specify this hardcoded value in your code allover the place each time you need to echo it. So it would be normally not one, may be even couple times in same file - whole this if
construction.
And if you use 'register' approach - you'll need only register this once. And just use it farther. No repeating if
and value is hardcoded only once.
The key should then be correctly in a file that gets loaded before reaching that point in the code. Either way it looks like you're trying to either:
def()
method in the Registry
and JInput
classes)What it appears you want to do (allow users to translate strings and use a default value if not present) is already possible with the example snippet I posted above, it's just a little verbose because there isn't a $default
parameter on any of the JText
methods or JLanguage::_()
.
Right now this just honestly feels like you're trying to work around defining a correct set of default language strings. I get there are use cases where loading strings into the catalogue outside storing them in INI files makes sense (I've looked at several Symfony addons that use the database for translations), but in all honesty JLanguage
is just not structured to be able to support a structure alternative to loading INI files and if there's a desire to support it it needs to be more thought out than a vaguely documented addString()
method which by most accounts goes against best, or even good, practices in Joomla's weak development environment.
because there isn't a $default parameter on any of the JText methods or JLanguage::_().
Technically there is a default value built-in in JText. It's the english textfile that is always loaded and is used for a string if there is no translation available.
def
or is it about keep Joomla being wheelchair?@Bakual please go deep into issue instead of "search keyword 'default' => 'Hey, there's default value"
please go deep into issue instead of "search keyword 'default' => 'Hey, there's default value"
That's not what I did. I just still don't get the point of this. I guess it is mainly because you want to avoid this:
- don't do any filesystem manipulations
But this would be the correct thing to do. I doubt you have a use case where you dynamically add and remove strings on the fly that change each day. Most likely the admin creates maybe a new field and then should be able to translate that. Then you could just write that string into a file when that custom string is added (to have your default value). Or even better, just tell the admin to use the already existing feature to add custom strings in the override.ini file. There is even an UI to do that in the language manager.
If I understand your intentions, you want to have the user create a new field which implies one or several new language strings. And then in the same form the user already specifies the "source translation" (aka "default"). So for example the english value of that field. That is then stored into the database.
However this is exactly what we're trying to avoid in Joomla. We don't store such strings into the database when they are supposed to be translated and we should not an API to encourage such behavior.
See for example how we support translations for com_fields. You can optionally enter a language string as label and description and it will be translated if the user also adds the corresponding strings to the overrides. Otherwise the value will be shown as is.
Or I completely miss the point of this PR.
@Bakual Well, still you'll generate some constants then by some good reason spelling of constant will change. You'll need to add parser script to go through users INI files and do your changes.
And overrides - yes. This PR is involving overrides logic, but really what would be a good practice:
if you thing that point 1 is good - let's check the dictionary...
It's up to extension developer to guide users to how to translate things, which constants to use.
Good luck for that! As these constants (and values) will be hardcoded and not present in any ini file, the Overrides Manager can't find them.
Also, as they do not target a specific language, debugging language will not show these as untranslated...
At least in com_fields, the site administrator would know about the constant created as well as the value (He/she created them...), and it would be his/her role to create the necessary strings in an override per language. Although this becomes cumbersome when many strings.
Note: let's not forget that the overrides were not implemented, performance wise, for a lot of strings.
@infograf768 I'll get my share of luck with that as soon as this PR will make it into repo.
According to @Bakual my approach is approach of com_fields + "out of box translation" - so performance wise - there is no difference.
I am not convinced. One should not count on "luck".
We can't even count on an automated way to add/create the new strings and values in overrides/en-GB.override.ini as these would only show when Overrides are filtered by client and en-GB language. It would need an important overhaul of the overrides manager with batch functions, etc.
++ a message telling the user "Warning! A new string (new strings) has (have) been added by extension x in overrides/en-GB.override.ini . If your site uses multiple languages, you should create overrides for this (these) language(s)..."
@alex7r
Initially i thought you wanted to override: JText::_('some_key') inside some other party code, that is out of your control (you cannot modify it)
$language = JFactory::getLanguage();
echo !empty($user_strings['some_key']) ? $user_strings['some_key'] : JText::_('some_key');
@infograf768 there's no relation to the 'override manager' in terms of prompting user about override ability from 3rd party extension in this case
@ggppdk not exactly right priorities, it's more like
echo (JText::_('MY_CONSTANT') && JText::_('MY_CONSTANT')!='MY_CONSTANT')?JText::_('MY_CONSTANT'):'My hard my_constant value';
And no, we must not allow to break translations of other extension so no extension will break one another.
But tell me, what's good practice and what is bad:
1)
echo (JText::_('MY_CONSTANT') && JText::_('MY_CONSTANT')!='MY_CONSTANT')?JText::_('MY_CONSTANT'):'My hard my_constant value';
...
echo (JText::_('MY_CONSTANT') && JText::_('MY_CONSTANT')!='MY_CONSTANT')?JText::_('MY_CONSTANT'):'My hard my_constant value';
...
echo (JText::_('MY_CONSTANT') && JText::_('MY_CONSTANT')!='MY_CONSTANT')?JText::_('MY_CONSTANT'):'My hard my_constant value';
...
echo (JText::_('MY_CONSTANT') && JText::_('MY_CONSTANT')!='MY_CONSTANT')?JText::_('MY_CONSTANT'):'My hard my_constant value';
...
JFactory::getLanguage()->addString('MY_CONSTANT','My hard my_constant value');
echo JText::_('MY_CONSTANT');
...
echo JText::_('MY_CONSTANT');
...
echo JText::_('MY_CONSTANT');
...
echo JText::_('MY_CONSTANT');
...
echo JText::_('MY_CONSTANT');
...
@infograf768 there's no relation to the 'override manager' in terms of prompting user about override ability from 3rd party extension in this case
I know. Even this is not considered in this PR...
So what the comment was about then?
I mean it's all going like "there is an issue prompting users at the overrides manager lets stop any joomla development and documentation because neither of this solves issue about prompting users at the overrides manager".
This PR has use cases, it allows code improvements, it gives more space and flex to developers.
And as I've mentioned in description: I'd like to allow this functionality when it needed, but not suggest developers to go this way first.
So what's the issue with all of this?
Technically there is a default value built-in in JText. It's the english textfile that is always loaded and is used for a string if there is no translation available.
@Bakual That is still reliant on translation strings being defined in an INI file. What is being proposed here is basically a way to fall back to a value defined in PHP if a key hasn't been defined in any INI file loaded into the active JLanguage
instance. Two different behaviors.
@alex7r This is really an edge case scenario and honestly looks to me more like a developer being lazy and not building proper default INI files. Yes I get your aim is to allow dynamically translatable keys, but this specific approach is more problematic than useful from a management perspective (the user doesn't know what the keys are until they start seeing them on the screen, you don't have an effective list to share with translators if you're trying to translate that content, and it effectively bypasses all of the existing tooling within Joomla to help with language management).
You can do exactly what you're aiming to do already:
echo JFactory::getLanguage()->hasKey('KEY') ? JText::_('KEY') : 'Hardcoded value';
Yes, it's more verbose than JText::_('KEY')
several times, but if you're really using the same constant multiple times then either in your workflow the value should be assigned to a variable or just translate the key using the existing workflow. The fact is this workflow is still only usable if you know what the key/value pair should look like (presumably you're probably basing default values on column names), you still have to know enough information to have a sensibly hardcoded default value so at that point you are still better off just putting it in an INI file and being done with it.
As for the method naming, methods named addX
or setX
imply they will always add or set a value. Using an adder that does not always add a value is anti-pattern. If you insist on having such a method then it should really be defineX
.
Well, still you'll generate some constants then by some good reason spelling of constant will change.
@alex7r If you're going to change constants, you have bigger troubles anyway. You would loose any existing translations and your users would surely love you for that.
But tell me, what's good practice and what is bad:
You wouldn't do it that way for sure. You would at least create a helper function to do those checks and then it already looks nicer again. Beside that there is an API to check for it.
And as Michael already said you probably do something wrong when you have to call the same JText multiple times.
@Bakual You're wrong about as if this PR would be merged no checks necessary, as Joomla will serve this.
@mbabker and @Bakual so once again we're ending up at the point of: "Why would we add common helper functions into the core? let's force everybody to reinvent the wheel".
@mbabker there's mainly three types of extension:
In my case there easily manageable functionality that's becoming a little bit not so easy without reading docs if you setting up multilingual site, but that's a reason.
This isn't a "common helper function" though. This is a "programmatically define new translation keys" function. This is the aspect I'm not in agreement with.
I do agree with making it easy for JLanguage::_()
and anything that uses it to define a default value to use if a key doesn't exist. That shouldn't cause the untranslated key to be added to the string catalogue with a value though (similar to if you call Registry::get()
and the key doesn't exist it just returns the default without assigning that default to the registry with that key). Right now you can do something similar with the code snippet I've posted twice but it has a little verbosity (which isn't necessarily bad, as much as people like to talk about DRY code I'm honestly working with something right now that has taken that principle to a point where things are TOO abstracted and DRY and honestly just makes some aspects of it harder to work with).
I think it is the wrong way to achieve the result, I agree with @mbabker @Bakual and @infograf768
Ok, it's not even 24 hours, what needs to be done is done:
Debug mode will disable this PR`s behavior so user can easily get list of untranslated constants and get constant to use for overrides.
May be a little bit over committed as now I see that it could been do with just changing
public function def($constant, $value)
{
if (!isset($this->strings[$constant]) && $value)
{
$this->_strings[$constant] = $value;
return true;
}
return false;
}
to
public function def($constant, $value)
{
if (!isset($this->strings[$constant]) && $value && !$this->debug)
{
$this->_strings[$constant] = $value;
return true;
}
return false;
}
but still I think this is better way as developer can list those constants without enabling debug mode.
@mbabker , @infograf768 any updates on new proposal?
What Michael suggested was to do something like JText::_('string', 'defaultvalue')
(like JRegistry->get()), however you want to still do the setting of language constants where he, me and JM all disagree with. You didn't change that part.
repetitive hardcoded values
As said already, if you repeatedly need to translate the same string you do something wrong.
JText get values to pass to string, so you can't add default without breaking default functionality
JText::() calls JLanguage::(). If you add that default functionality to both methods it would be possible easily without messing with the language strings and without having to change debug behavior or any other behavior.
I am closing this here, nobody besides the author of the PR thinks it is a good idea. I can add this will not go into 3.7
Status | Pending | ⇒ | Closed |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2016-12-20 19:38:36 |
Closed_By | ⇒ | rdeutz |
could you explain the precise use of this? for example with an extension using the new method.