? Pending

User tests: Successful: Unsuccessful:

avatar alex7r
alex7r
18 Dec 2016

Dynamically add string for Dynamic strings
For example: COM_EXAMPLE_DYNAMICFIELD_LABEL

Summary of Changes

Adding ability to set custom strings on fly
Don't allow to force strings change/reset so one extension couldn't damage another

Test instructions

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:
screen shot 2016-12-18 at 08 48 56

Documentation Changes Required

May be added to documentation, but should be marked with:
Try to avoid use of this if possible; Language files implementation first attitude

In the end of the day

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.

avatar alex7r alex7r - open - 18 Dec 2016
avatar alex7r alex7r - change - 18 Dec 2016
Status New Pending
avatar joomla-cms-bot joomla-cms-bot - change - 18 Dec 2016
Category Libraries
avatar alex7r alex7r - change - 18 Dec 2016
Labels Added: ?
avatar infograf768
infograf768 - comment - 18 Dec 2016

could you explain the precise use of this? for example with an extension using the new method.

avatar dgt41
dgt41 - comment - 18 Dec 2016

I have tested this item successfully on a2b8885


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/13264.

avatar dgt41 dgt41 - test_item - 18 Dec 2016 - Tested successfully
avatar dgt41 dgt41 - change - 18 Dec 2016
The description was changed
avatar joomla-cms-bot joomla-cms-bot - edited - 18 Dec 2016
avatar alex7r
alex7r - comment - 18 Dec 2016

@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.

  • don't do any filesystem manipulations
  • still allow to override/translate those stings by native joomla way
avatar anibalsanchez
anibalsanchez - comment - 18 Dec 2016

I have tested this item successfully on a2b8885

Test OK


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/13264.

avatar anibalsanchez anibalsanchez - test_item - 18 Dec 2016 - Tested successfully
avatar Bakual
Bakual - comment - 18 Dec 2016

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.

avatar ggppdk
ggppdk - comment - 18 Dec 2016

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

avatar infograf768
infograf768 - comment - 18 Dec 2016

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?

avatar alex7r
alex7r - comment - 18 Dec 2016

@Bakual

  1. So you can translate those values
  2. Allowing to write flexible code

@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!

avatar alex7r alex7r - change - 18 Dec 2016
The description was changed
avatar alex7r alex7r - edited - 18 Dec 2016
avatar mbabker
mbabker - comment - 18 Dec 2016

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.

avatar alex7r
alex7r - comment - 18 Dec 2016

@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.

avatar mbabker
mbabker - comment - 18 Dec 2016

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:

  • Create a "define if not exists" API endpoint (in which case neither an adder or a setter method name really describes that action, the closest we have to that is the def() method in the Registry and JInput classes)
  • Create a "use fallback if not exists" parameter similar to many other getter methods in the API

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.

avatar Bakual
Bakual - comment - 19 Dec 2016

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.

avatar alex7r
alex7r - comment - 19 Dec 2016

@mbabker

  1. there no "use DB for translations" here - it's "use INI to translate DB values" and this is by far different kind of things.
  2. I don't get your point: is it about renaming method to def or is it about keep Joomla being wheelchair?
    Not even good practice? And what's then would be good? Really interested to hear from 'Joomla! member who says "Joomla has weak dev environment" and "50%+ of code and methods in Joomla core are fully"'... Great marketing by the way...

@Bakual please go deep into issue instead of "search keyword 'default' => 'Hey, there's default value"

avatar Bakual
Bakual - comment - 19 Dec 2016

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.

avatar alex7r
alex7r - comment - 19 Dec 2016

@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:

  1. to leave CONSTANTS allover the view and force user to go to override to set them up
  2. to leave chance to the users to override things with overrides, but do most pretty view out of box

if you thing that point 1 is good - let's check the dictionary...

avatar infograf768
infograf768 - comment - 19 Dec 2016

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.

avatar alex7r
alex7r - comment - 19 Dec 2016

@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.

avatar infograf768
infograf768 - comment - 19 Dec 2016

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)..."

avatar ggppdk
ggppdk - comment - 19 Dec 2016

@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)

  • but if you want to do it in your own code, then when why you do not change your code and use something like ?:
$language = JFactory::getLanguage();
echo !empty($user_strings['some_key'])  ?  $user_strings['some_key'] : JText::_('some_key');
avatar alex7r
alex7r - comment - 19 Dec 2016

@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');
...
avatar infograf768
infograf768 - comment - 19 Dec 2016

@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...

avatar alex7r
alex7r - comment - 19 Dec 2016

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?

avatar mbabker
mbabker - comment - 19 Dec 2016

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.

avatar Bakual
Bakual - comment - 19 Dec 2016

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.

avatar alex7r
alex7r - comment - 19 Dec 2016

@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:

  1. easily manageable
  2. complicated in management for no reason
  3. complicated in management for a reason
    Yes we need to get rid of point 2, but we can restrict 3 option, because really big and flexible functionality mainly can be set up easily.

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.

avatar mbabker
mbabker - comment - 19 Dec 2016

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).

avatar rdeutz
rdeutz - comment - 19 Dec 2016

I think it is the wrong way to achieve the result, I agree with @mbabker @Bakual and @infograf768

avatar alex7r
alex7r - comment - 19 Dec 2016

@mbabker Flexible systems aren't easy to work with, but those are better in long run.

Ok, give me another 24h without closing this PR, so I could add commit and wouldn't have to repeat whole this conversation into another PR.

avatar alex7r alex7r - change - 19 Dec 2016
The description was changed
avatar alex7r alex7r - edited - 19 Dec 2016
avatar alex7r
alex7r - comment - 19 Dec 2016

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.

avatar alex7r alex7r - change - 19 Dec 2016
The description was changed
avatar alex7r alex7r - edited - 19 Dec 2016
avatar alex7r
alex7r - comment - 20 Dec 2016

@mbabker , @infograf768 any updates on new proposal?

avatar Bakual
Bakual - comment - 20 Dec 2016

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.

avatar alex7r
alex7r - comment - 20 Dec 2016

@Bakual but debug now allows to list and see untranslated strings.
You can't use default value in the way you propose:

  • repetitive hardcoded values
  • JText get values to pass to string, so you can't add default without breaking default functionality
avatar Bakual
Bakual - comment - 20 Dec 2016

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.

avatar rdeutz
rdeutz - comment - 20 Dec 2016

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

avatar rdeutz rdeutz - change - 20 Dec 2016
Status Pending Closed
Closed_Date 0000-00-00 00:00:00 2016-12-20 19:38:36
Closed_By rdeutz
avatar rdeutz rdeutz - close - 20 Dec 2016

Add a Comment

Login with GitHub to post a comment