Goal
As part of the localization update integration in core, we are looking to add source tracking functionality in interface translations. The l10n_update module tracks localization source for translations, so sites can customize community provided strings and retain those customizations.
Implementation plan
- Add a new column in the locales_target table. This is called l10n_status in l10n_update. Not sure we want to call it status, but it sounds like it would work for now.
- Add constants for the status values. LOCALE_COMMUNITY_PROVIDED, LOCALE_USER_PROVIDED or something along these lines.
- Fill these values to LOCALE_COMMUNITY_PROVIDED by default (when .po files are imported)
- When manually editing strings on the user interface set to LOCALE_USER_PROVIDED
- When importing a .po file, extend options to possibly overwrite user provided strings (see l10n_update for options)
- When importing a .po file, also extend options to specify if the .po file was user provided or community provided (maybe this is covered by previous option?)
Comment | File | Size | Author |
---|---|---|---|
#123 | custom-string-changelog.patch | 728 bytes | Gábor Hojtsy |
#119 | 1445004-119.patch | 45.37 KB | Sutharsan |
#115 | 1445004-115-import.png | 125.63 KB | roderik |
#115 | 1445004-115.patch | 46.96 KB | roderik |
#115 | 1445004-108-115-interdiff.txt | 3.24 KB | roderik |
Comments
Comment #1
Gábor HojtsyMark for sprint.
Comment #2
roderikDiving in.
Comment #3
roderikOK -- the first part (being 4 out of 6 points above) is done, plus a suggestion from Gabor: provide a filtering option for the statuses, in the translation screen.
I'll continue this week, but upload what I have now. There's @todo's on basic stuff like thinking about the name of the added column... I'll rethink those when I did the last part of this issue.
Filtering options I added into an existing dropdown. This means that not all theoretical filtering options are possible (like 'untranslated strings plus those entered on the site') but I think that's fine.
Comment #4
roderikSetting to review for naming of constants, naming of UI stuff, etc. But I'll rethink that myself, when done with the rest of the issue. So it's still CNW too.
Other incoming suggestion from Gábor: make the added 'translation status' a filtering option in the .po export.
Comment #5
Gábor Hojtsy@roderik: thanks for working on this! Can you continue bringing this forward?
Here are comments based on a code review.
I think these will need to be made dynamic once the "custom strings export" feature is in, which should let you import strings as custom even on the import UI.
First lines of phpdoc should be summary and on one line (max 80 chars). If you need more background info add it on a second line but separate with a linebreak from the first.
I agree naming this 'status' in the schema, _TARGET_ in teh constant and source on the UI (and type in the dropdown :) is a bit too much variation ;)
What about sticking to source all around?
I don't know really great words for these values, but they should at least be t()-ed for display. I think t('Custom') and t('External') would be good.
Comment #6
Sutharsan CreditAttribution: Sutharsan commentedlocale_update_8001() should migrate data from l10n_update. Check for the existence of 'l10n_status' column in the same table and copy the data into the new 'status' field.
Changed the naming of the translations to 'custom' translations. 'Entered on this site' may be confusing if a po-file is uploaded. I've considered 'default', 'original', 'community' and 'custom', 'overridden', 'local'. But chosen the text below to be the most straight forward and least jargon.
If we agree on this naming, we could change the field name 'status' to 'override'. (Not included in the patch)
The translations overview page does not need a 'status' column. The content of this column is 99(.9)% of the time 'default' According to the User Interface guide this should be avoided.
In locale_translate_edit_form_submit() only set the status to LOCALE_TARGET_USER_PROVIDED if the string actually changed. When a site uses multiple languages, the translation page presents multiple translatable fields. Only the translations which were changed should be flagged.
Comment #7
Gábor HojtsyMarking needs review for testbot. Still needs to address my comments and new suggestions from Sutharsan.
Comment #9
roderikBoth, thanks for your comments. Sutharsan, thanks for the code changes with nearly all your comments.
I defer to Sutharsan's experience on naming, and personally like the term 'override' for the database field.
Constant names/strings have been changed to match the 'default/custom' in the proposed description. Note their names are now quite generic, because the 'property name' is not included in the constant names##, and DEFAULT/CUSTOM are pretty generic terms. I believe in this case, that's OK...
Further:
-----
## I'm probably not being clear, however I try to describe that. I mean the construct 'entity.propertyname=value' here maps to 'locale_target.override=value'. The constants LOCALE_TARGET_DEFAULT and LOCALE_TARGET_CUSTOM seem to be giving the 'entity' a value. They don't even name the 'property' which the value actually belongs to. But LOCALE_TARGET_OVERRIDE_DEFAULT and LOCALE_TARGET_OVERRIDE_CUSTOM don't seem clearer to me. Same if we'd put STATUS there.
Comment #11
Gábor HojtsyThanks for continuing the work on this! It is getting better but IMHO still needs some discussion. The real trick here is IMHO not the functionality itself but how to make it intuitive for users so we need to get that right :)
Queries like this are very good candidates for conversation to db_select() instead of string manipulation.
In this snippet only, we call this an override, then a translation status, then a kind of translation :/ Can we figure out a terminology that can be used all around? Or at least limit the variance to two?
Eg. "type", "source", "customized"... I think we need some more brainstorming here...
Let's say we use "customized". That works as a column name, it works as a label, and we can say "base translation" and "customized translation" referring to the "customized" property.
Customized is also used in the menu_links schema to essentially mean the same thing:
This should have been 'override', right?
The table column should be dropped after its data being migrated I think.
Comment #12
Gábor HojtsyUpdated patch based on my comments.
- renamed constants to LOCALE_CUSTOMIZED and LOCALE_NOT_CUSTOMIZED
- added more docs on the constants
- passed on customized flag in import process (yes, this shows the whole import code is a huge mess and needs refactoring, we are doing it in a small part at #532512: Plural string storage is broken, editing UI is missing and will do it a lot more later; adding in this new feature now is not an issue IMHO on that front, we have refactoring and new feature cycles constantly going to optimize the patch flow :)
- refactored the _locale_export_get_strings() code to use dbtng
- added checkbox UI on import form for customized flag
- reworked customized flag selector as a radio group on export form, cleaned up text
- fixed the schema
- removed l10n_status in upgrade path, since we have its data migrated
- made 'customized' its own select box / option and made it a dependent select box which only shows if the translation select says only translations
Did test the search UI changes. Did not test import/export.
Search UIs:
Import UI change:
Export UI change:
Comment #13
Gábor HojtsyComment #15
Gábor HojtsyHelps if the query is actually executed on export. Will eventually need test when we get to an otherwise passing patch with a finalized UI :)
Comment #16
Gábor HojtsyComment #17
Gábor HojtsyComment #18
Sutharsan CreditAttribution: Sutharsan commentedExcellent work Gábor You couldn't wait untill we did this ;)
Comment #19
Gábor Hojtsy@Sutharsan: well, its not done yet at all. Can you or roderik help with adding tests (import stuff as customized, edit other stuff, export stuff only customized, only non-customized, etc)? He pointed out to me in email that he likely does not have time anymore this week, so moving to unassigned.
Thank you all for working on this!
Comment #20
roderik@Gábor: you're right in unassigning me - but I could put in some time for a little review & extra change.
(Naming "customized": ah. consistency in is nice. UI works well. Constant names are growing on me, I'm starting to like them.
Dependent checkboxes: ooh, shiny! Wasn't used to those yet, hence me putting the stuff in one.)
--
There should be an extra import mode now - the idea copied from l10n_update, though not the exact implementation:
Basically, if you import something as 'customized' and then later you import newer 'default' translations, you should have the option to not overwrite your customized translations, only the 'default' ones.
I also made it so that it would work the other way around (i.e. importing a newer 'customized' file overwrites only 'customized' strings, never 'default' ones). Not sure if there is a realistic use case for that.
It makes for a horrible description in the import screen, though. I'd like to have another pair of eyes on that.
Also, as Gábor said, still Needs Work for tests.
Comment #21
Gábor HojtsyI agree it would be great to somehow shorted those sentences dramatically :) Let's see these?
What do you think? (This does not use the same order, and I think this new option would be the best new default, no?)
Also on re-reading the text for the custom checkbox that I wrote, I think we can easily loose the "you import" wording, its is pretty overkill :) Smarter text++ :)
Comment #22
Lars Toomre CreditAttribution: Lars Toomre commentedWhen this patch gets re-rolled, the docblocks like this one need some work.
The @param $customized needs the (optional) phrase to start the description as well as a statement of what the default value is. Also, I thought type hinting was recommended for D8 docblocks. Hence, something akin to the below would be more appropriate (wrapped at 80 characters):
Other parameters on some of the functions being modified in this patch also are missing the (optional) sting as well as type hinting. I would suggest that they get corrected in this patch as well.
Comment #23
Gábor HojtsyOk here is a more dramatic rework of the import UI in part based on just pure simplification with consultation with @yoroy. Sorry did not implement Lars' suggestions yet. Also did not align the actual import code to support the new UI. In case we want to make any further changes. I think we basically want to fill in a matrix of defaults for the protection of existing translations and then let users choose as they want. The defaults would IMHO be (in the name of protection by default):
(Edit: fixed issues in the table :) The three checkboxes let users provide their choice along the lines of this matrix basically, but it looks much simpler than that hopefully :)
Comment #24
Gábor HojtsyThere goes the export screen with similar rigor :) That was also pretty fascinating. Instead of using two fieldsets, it used #type item's as headers (OMG) and then shared the same submission function among two forms. It did use the #type actions wrapper for buttons, which is good practice to use, so applied that to the import screen to though (no visual change, just FAPI best practices). Again employed some states to hide irrelevant stuff when not useful.
Overall the goal is when we introduce yet another new feature here, we make it so as simple and straightforward as possible. Since the forms were complex enough already, this looks like we can't escape fixing them up. Sorry if this looks like a bit of an overkill but IMHO its a timely goal. Yes, the internal APIs are also bad, but we need to fix that elsewhere, because that is *way LOT* more code.
So if these UI tweaks look good, we need to re-fix the import/expor screens to work with these vs. the custom flags.
Comment #25
Gábor HojtsyMost likely not going to pass, just handing this in so its easier to figure out where did I break all kinds of stuff in tests :D And to get review on the UI.
Comment #26
drifter CreditAttribution: drifter commentedI think people will have trouble figuring out what a "customized translation" vs. a "non-customized translation" is, and so they'll have trouble selecting the right checkboxes. How about keeping a set of radio buttons with better descriptions, something like:
New translations will be added. For strings that already have translations:
() Don't overwrite any existing ones
() Only overwrite built-in translations.
() Only overwrite custom translations.
() Overwrite all existing translations
I think this makes the "safe" option and the "these are the translations I want" options more clear.
Comment #27
kalman.hosszu CreditAttribution: kalman.hosszu commentedI agree with drifter about the import page modifications, and I think a description on the export page should helpful to explain what does "customized translation" stand for.
Comment #28
Gábor HojtsyHere is a patch with an updated export screen. I've theoretically built in the backend support for the export to do as advertised on the UI, but did not really test (yet). Added a third option for completeness. So you can do things like 'export strings I did not translate yet to Afrikaans' or 'export things I customized from the community translations for Afrikaans'. If you select a language but do not check any of the checkboxes, the file would be totally empty, so in that case I choose to fall back on exporting a template. We can also throw back a form error for that case if that sounds better.
@drifter, @kalman.hosszu: great feedback. I'm wondering if we can explain the customize process better by leading the user with that. Remember, we want to build in l10n_update, which would feed the site with community translations and the ones edited on the UI (or imported as custom) are customized. I think adding an explanation like "Custom strings are either ones you edited the translation of on this site or imported as custom" is especially good. We can bury this in the help text later if we want to / need to but not sure it should be in the form.
So I think we might want to lead with a UI change like this to let people learn what is customized? :) Is this is too radical? :)
Comment #30
Gábor HojtsyTests fixed for import/export and import code made work with the current options.
@drifter: BTW "built-in translation" is not really what is going on right, the translations are in no way built-in, they are "stock", "provided by the community", etc. We have some more terminology discussion above that you can read up on.
Comment #31
Gábor HojtsyAlso loose the unneeded LOCALE_IMPORT_* constants and fix one remaining place of invoking the import API with the old constant instead of array of options. (Should stop this for today :).
Comment #33
Sutharsan CreditAttribution: Sutharsan commentedWe don't have to agree yet on what is the best wording. Lets see if we can come up with two of three alternatives, make simple mockups (or write it in code) and try it out with a few people.
Comment #34
roderikOh. Wow. Sweet :D
Observations:
So yes, this needs good help text to ease the user into the options. Both on the explanation of the difference between custom vs. non-custom, and guiding the user with as little pain as possible, to what they really need
The code (Gábor's matrix) sets "do not overwrite non-custom" by default, if the imported file is non-custom.
So the reason for that is that this is the 'safest' option. Not that it's the 'most commonly used' option, because it isn't. Is that a fair statement to make?
Patch contains no functional changes since patch 31, just a few minor things that caught my eye. I didn't test, only read code.
Comment #35
Gábor HojtsyComment #37
Gábor HojtsyFixed most tests by using the right nested form ID syntax (doh) and not attempting to delete non-existent translations.
Comment #39
Gábor Hojtsy#532512: Plural string storage is broken, editing UI is missing landed, so many import/export things needed to be rerolled. Here is a new version. Will most likely still fail.
Comment #41
Gábor HojtsySeveral update functions landed since, so needed to bump the number quite a bit.
Comment #42
Sutharsan CreditAttribution: Sutharsan commentedBumping the testbot.
Comment #43
jthorson CreditAttribution: jthorson commented#41 and #42 are testbot-breakers ... for some reason, qa.d.o has troubles parsing the test result. Please do not requeue.
I hope to get back later today to debug what the root issue might be.
Comment #45
Sutharsan CreditAttribution: Sutharsan commentedThe patch corrects a column definition. That may explain the broken test. But testing this patch fails locally on the po import test. But importing the same files manually passed. Lets see what the test bot thinks about it.
Comment #47
Sutharsan CreditAttribution: Sutharsan commentedThese are exactly the tests that failed when I ran the tests locally (that's at least something). It looks like the plural formula is being overwritten. But when importing manually all is fine. Test files taken from the code are attached here.
Comment #48
Gábor HojtsyI know the test fails are more likely do to invasive changes we make in the import conditions. They mean somewhat different things after this patch. I took some time looking there earlier above extensively but did not reach conclusions unfortunately. I think we should re-evaluate the correctness of changes in conditions in the import process.
Comment #49
saltednutSimpletest did not have the javascript behavior to automatically uncheck 'Include non-customized translations' so.. overwrite_options[not_customized] was always defaulting to 1. Patch forthcoming....
Comment #50
saltednutSubmitted for testing...
Comment #51
saltednutComment #52
saltednutImport
Export (Source Text)
Comment #53
saltednutExport (Language Specific)
Comment #54
pixeliteFor the import and export UI, I agree that it's not clear what custom translations are. I think we should add some help text to the list of options: 'Custom translations are translations which haven't been downloaded from a centralized source like localize.drupal.org'.
The word 'Non-customized' could also be replaced with 'default'.
I also think that in the Import UI, the phrase 'Import contains custom translations' should be replaced with 'Import contains customized translations' to make the label consistent with the other options.
Comment #55
mbyrnes CreditAttribution: mbyrnes commentedThese look really good! Definitely a simplified UI improvement with more fine grained options.
Here is a summary of feedback from the admin perspective looking at the current UI:
EXPORT
Source Text only option:
When I go to the export screen, I am looking for a language. Source text only doesn't really make sense as the sane default. Ideally it would be the main language on the site default that would be in here and that would be a non default option.
If this option was selected, it would make sense that it be explained what exactly it would deliver or what a use case might be. Why would I select this?
When Language is selected:
We should assume that most exports will include the entire file, so having the 3 checkboxes visible with the option to generate a blank file seems a bit confusing.
Perhaps an option to view these as more advanced options for people who select the option may be helpful.
"Customize content of file exposes the options" ie. Include customized translations, include non-customized translations, and include untranslated text.
IMPORT
When the language is selected, the three checkboxes don't seem related. The first check box "Import contains custom translations" describes the contents of the file. The 2nd two check boxes are actions that should be taken upon importing.
Because these are different groups, I suggest that we move the import contains custom translations to be nearer to the file field.
Terminiology:
Overwrite existing non customized translations
Overwrite existing customized translations
These options are only one word apart and it may be confusing for people. I don't have a current solution and I do like the 'customized' terminology. I just worry that they are visually similar and require a bit of mind bending to figure out exactly what this would get you.
One idea would be to possibly create summaries for each of the permutations. For example if you selected "import contains custom translation" AND "overwrite existing customized translations", a message would be given such as "You have selected file X to be imported, the updated translations in your file will replace what currently exists on the site."
Comment #56
pixeliteFor the import UI, in order to make it clearer that the 'Import contains custom translations' checkbox is all-or-nothing, I think we should move it to a separate radio button field.
Label: This import consists of custom translations, Checkboxes: Yes/No
Comment #57
BerdirCoding style review.
Looks like a tab there on the last line with the }.
More tabs and trailing spaces.
Comments should be on a separate line, even for cases like this one. Not sure how the other rules apply here (like having a proper sentence ending with a .)
Same here.
Core *usually* doesn't deal with contrib modules in the upgrade path. Even if stuff is moved into core (e.g. fields in D7).
Just wanted to point this out, I'm fine with keeping it if is ok'd by others.
The '=' is not necessary, that's the default.
Comment #58
Sutharsan CreditAttribution: Sutharsan commentedStill 'needs work' for #54 - #56
Comment #59
Sutharsan CreditAttribution: Sutharsan commentedComment #60
Sutharsan CreditAttribution: Sutharsan commentedExport, Source Text only
When no language is available (system language only) a text is displayed instead of the (one option) select list.
Export, When Language is selected
Language default value changed to the site's default language.
Added a checkbox to hide/display the export options. Or should this be a collapsible fieldset?
Changed 'Include non-customized translations' to 'Include default translations'
Import
In order to explain a concept, it needs to have a name. Instead of 'default translation' and 'customized translation' I looked for a name that give these translations a natural state above the other translations. Base translation and Priority translation is my choise, but I am open to suggestions. I only changed the import and export interface, no name changes in the code yet.
Comment #61
Sutharsan CreditAttribution: Sutharsan commentedTry again ;)
Still needs work, I need to check the test. But would love feadback on the interface.
Comment #62
Sutharsan CreditAttribution: Sutharsan commentedNeeds usability feedback on using a checkbox or collapsed fieldset to hide/show details of customized export.
Comment #63
Sutharsan CreditAttribution: Sutharsan commentedThe fieldset variant:
Comment #64
Bojhan CreditAttribution: Bojhan commentedI would prefer the option of using a collapsed fieldset. Although the "collapse upon clicking a checkbox" is a possible pattern, it is not one that performs very well with users (it is is magic to them, when a checkbox collapsed into more optionns).
Given that this is functionality, that looks like very experty (not for the 80%) - I would agree with the idea of putting them in a collapsed fieldset..
Comment #65
Bojhan CreditAttribution: Bojhan commentedComment #66
Gábor HojtsyFieldset looks good.
Comment #68
Sutharsan CreditAttribution: Sutharsan commentedTest now pass locally.
Comment #69
Schnitzel CreditAttribution: Schnitzel commentedJust heard about this Issue the first time.
I think it is a really good Idea, but I would suggest to call the "Translation Types" different:
- Custom Translation
- Community Translation
Comment #70
Sutharsan CreditAttribution: Sutharsan commentedAfter a day, I realize that my 'priority' naming idea was not so well thought out. We are not used to calling things names in Drupal. Lets revert to 'default' and 'custom(ized)'.
But it made me realize that we are building power user functions into core here. First (second and third) time users of Drupal wil not import and export po's. All they want is "one button". Select a language and the're done. They may not like the translation, but bothering them with export a pot file, grab a translation tool, import a po file is way to far. And we are busy adding options to control yet another layer, the customized translation string. If we want to smoothen the learning curve the least we should do is use sensible defaults and hide them (fieldset). Better would be to move these interface options into a contrib module. But best we could do is move the complete import and export interface to a contrib module. Once we have Localization Update module in core, we should leave import and export to the power users which are best served by contrib.
Comment #71
Gábor Hojtsy@Sutharsan: I would not be comfortable marketing Drupal 8 as a multilingual CMS if it does not let me change the interface translation, only if I go and edit obscure formatted .po files and then somehow re-import them on a one-button UI to reimport everything (which then might overwrite that file from a remote copy and I get lost all my changes). I think its both normal to assume that localize.drupal.org or any other localization server will not provide 100% translations and people need to work with plugging in the holes and that people will not 100% agree with the translation. Both are very current problems of people and the last one are even cause daily problems in translations teams.
I think we are making huge improvements to the import/export screens here already, so that is a usability improvement. And second, we need to build in custom string tracking because most people will need to use the translation UI to touch-up / extend on the built-in translation and we need this information for deployment/staging and later for a contrib module to let people contribute to the community their suggestions right away too (currently in l10n_client).
My thinking.
Comment #72
Sutharsan CreditAttribution: Sutharsan commentedI agree we need the plumbing, but do we need to add all possible options into the user interface. Yes, we need to add a custom translation to database and the API, yes l.d.o translations will never be 100%, and yes there need an interface to modify the default translation, yes these custom translations need to be treated different from the imported l.d.o translations. But I argue against bells and whistles for inexperienced users. For example the option to control whether imported translations will override the default and/or the custom translation, the options to export which flavor of translation (default, customized, untranslated). Using po files is not for the faint of hart, history proved this and lead us to build l.d.o. I do agree on the need for the underlying mechanisms which we are building in this issue. But to me core is not the place for full featured interfaces for power users.
[edit] some text changes
Comment #73
andypostThis issue require focus - there's to much context of translation forms!
There's a different angles to me here:
1) Developer (site builder) - need to translate config, some custom module's provides strings to UI of site's editors
2) Translator (site editor) - need to translate content, layout options, actions (links, buttons, rules) probably some custom UI elements (accordion, slider)
We could use the same element to translate strings and probably separate storage for different kind of strings
With customized bit we gets another dimension in strings' storage
so it makes queries slower and we need different strategies for caching
The UI could be implemented in separate issue, so if we have no time for UI we still have storage, cache and api and contrib project to grow better UI
Comment #74
Gábor Hojtsy@andypost: no this issue has a very clear focus. 1. It is only about strings coming from source code (not about translating config). 2. It does not store a customized and non-customized translation and does not use this bit at all in lookups (ie. will not store more copies of the data and will not slow down any lookup queries).
@Sutharsan: the .po import UI is already a power user tool if/once we add the l10n_update module. We are not moving ahead on that front much other than this patch (and this patch is locked in argue-land now anyway). So I think people who do end up using the automated l10n_update tools we want to build-in will not use this much anyway, and yes, it will be somewhat of a power tool. I still think if they want to stage/deploy their custom translations from a site to the live version, this import/export tool is the only thing we provide in core (outside of installing more contrib power tools), so depending on the use case, this looks like a basic tool for doing your deployment. Anyway, we are not moving forward with this one or any other of the l10n_update issues, so its hard to assume what would be ready by Drupal 8.
Comment #75
Sutharsan CreditAttribution: Sutharsan commented@gábor: I'm glad to read that we have more common ground, than I initially thought. I have no intention blocking this issue. In fact I continued on this issue again to make another small variation of the interface. It's difficult to find the right terminology.
Should we update the module's help text. And should we anticipate in the text on (automatic) translations update?
Comment #76
balagan CreditAttribution: balagan commentedFor me this new UI looked quite straightforward, but it is better to be on the safe side with being as clear as possible.
Comment #77
Sutharsan CreditAttribution: Sutharsan commentedCan't really improve this any more. I've tried different layout variations, but none did make it clearer non better layout. The patch changes only the 'priority' wording back to 'default' and 'custom(ized'). I left the help text unchanged as the translation handling is currently in flux and don't know where it will end.
Comment #78
Gábor HojtsyAll right, I see @pixelite brought back the suggestion to use 'default' vs. 'customized' instead of 'non-customized' and 'customized' that we used for some time. I see @Surtharsan likely agrees. If people overall think this is better terminology, then go with that. I don't like it personally because (a) it is not in Drupal by default, it still needs to be downloaded (b) it can change overtime as translators work their way through fixing issues and extending community translations (c) the 'default' wording makes me feel like this is a given, I think it disconnects people from the fact that the production of those is also an ongoing process and is not 'done' for them per say (d) I can import new defaults that overwrite the old defaults.
I thought the best wording we found to signify this was the customized/non-customized distinction. If people believe 'default'/'customized' expresses the same thing, then let's go with that.
Otherwise just a minor note: "Treat imported strings as custom translations." has a dot at the end, while we don't do that on checkboxes, right? We don'd do that on other checkboxes in the same form.
Comment #79
eigentor CreditAttribution: eigentor commentedA very quick scan of the UI options from someone to whom even the concept of customized translation sets is completely new.
For me, maybe not wanting to use the feature it means more checkboxes. So in order not to bother me but to provide the people who want to use it with the extra power:
1. Make clever defaults so I do nothing wrong
2. An option that rather hides the extra options and is called "options" or "advanced options" or whatever like in http://drupal.org/node/1445004#comment-5779464 looks good, as it employs UI patterns that appear familiar to me.
Comment #80
Gábor Hojtsy@eigentor: that is what is happening in the current patch yes :)
Comment #81
eigentor CreditAttribution: eigentor commentedGabor asked for UI feedback.
Instant reactions to the new UI which I understand is rather on the right side of http://drupal.org/node/1445004#comment-5673836
Uh, oh, three checkboxes, which ones do I choose? Somehow fear to do something wrong.
Same with old interface, but if I am a fearsome person I choose "only import new, don't overwrite" and feel this will most probably not break anything.
Now I have three options
* import contains custom
* Overwrite existing customized
* Overwrite existing non-customized
Uh, oh, what?
If I was new to Drupal I would be completely confused and am even now...
I only want to import a translation and have no idea if it is custom or not, but I do not want to break any stuff I already have...
Would advocate to provide clever default settings or somehow name it in a way so I know how to import a regular .po file I got from localize.drupal.org or some official download place.
I guess the people that import customized translations know what they are doing. So these people would be a very small minority, and somehow the entire custom translation thing would be an "advanced option" for me.
Comment #82
Gábor Hojtsy@eigentor: the current defaults are supposed to be the best guess for default behavior. They are not going to overwrite your existing data. Is the current Drupal 7 screen better? (see comparison in http://drupal.org/node/1445004#comment-5673836).
Comment #83
Sutharsan CreditAttribution: Sutharsan commentedTo aid the UI evaluation, some screenshots with the #77 patch applied:
Import
Export
For a default import and export settings we need a default scenario. I wrote a few, but note that I have little input from the real world of maintaining multilingual sites.
Which scenarios are most likely? On which should we base our default settings.
Comment #84
Gábor Hojtsy@Sutharsan: I think the (4) translation deployment scenario is most likely. In that scenario, people would export their custom translations only and import their custom translations. **However** we don't have any of the automated imports to be built, so the current most likely scenario is "I've downloaded this .po file from drupal.org and need to import it", which is what the current defaults are aimed at. I think once/if we introduce automated .po file download + import, we can talk about revisiting this screen to have better defaults in that scenario. Building this prematurely for a state that we don't know if we will reach is not a good idea IMHO.
Comment #85
eigentor CreditAttribution: eigentor commented@Gabor: right, the D7 screen is not that intuitive as well :)
I did not know that plural form bit until now, is this brand new?
The problem I stil see is: I think the user needs to choose one of those three options to import his .po file. The two old options still have me wondering every time if I am doing it right. With the three new ones, imagining I was a user new to drupal I have a very hard time choosing one as I understand them even less.
It is that all three sound a bit intimidating to me. But I guess "Overwrite default translations" would equal the old overwrite option and "Import Strings as custom translations" would be equal to "keep old, only import new"?
Now the challenge would be to name the three new ones in a way the casual user confidently chooses one.
Which one is chosen by default?
At last I think I am getting what this custom translation thing is all about: Someone has changed some translations in his current version of Drupal, and the new system makes sure he can safely import .po files without losing them, while still overwriting default translations?
Going really fancy there might be a mechanism that detects if any custom translations are there and only shows checkboxes / radios relating to that in that case. This would make the interface simpler for people who have not translated any string and just wanna import an innocent .po file.
But this might complicate matters on the programming side.
Comment #86
Gábor HojtsyNo. There is one checkbox where you tell the system whether your file contains your own custom translations or it came from the community (yes/no). Then there are two checkboxes where you tell the system whether to overwrite the non-custom and the custom translations that exist respectively. If you click you are importing a custom translation file, it will automatically check "yes" for overwriting non-custom strings (called default on the current UI). If you import a non-custom file, the defaults will be no overwrites (no checkboxes checked). So the sensible defaults we made up is that either no checkbox is checked, or the first two are (if the first one is). Then you can tweak it from there. So the upload, the dropdown and the first checkbox tells us what the file is, and the two last checkboxes tell how it is going to be processed in case there are conflicts with strings already in the DB. In that sense, the last two checkboxes could be the advanced options for the import.
Exactly!
That would require a four step process (1) you upload your file, ie. fill in the first three form elements (not the two last checkboxes) (2) we import your .po file to a temporary holding space somewhere and compare each strings to the data in the db, and devise if we need to ask the questions in the last two checkboxes (we very likely will need to) (3) we ask those questions (4) we import the file based on the answers to those. The current solution is a two step process, you provide all the data and then we do the import. I don't think moving to a four step process while we'd need to do the further questions almost all the time is a good idea.
@all: also note that the import UI now says "default translation" while the export UI says "base translation". Would be good to unify these. (I still think non-customized was fine :)
Comment #87
Sutharsan CreditAttribution: Sutharsan commented@eigentor, This customized flag for translations is introduced by this patch to allow the admin to override translations and prevents them from being overwritten by automated translation updates like the Localization Update module. Translations edited via the translation UI will be marked as customized. Translations imported from l.d.o by Localization Update are not marked customized (e.g. become non-customized or default translation). In the same way, manually imported po files from l.d.o should become default translation. Customized translations are the admin's realm, default translations are the system's realm. Customized translations give the admin full control, default translations allow override by automatic updates.
Comment #88
Gábor Hojtsy@eigentor: thought some more about this, the right defaults are really dependent on the situation :) If you are building out your site and importing translations from the community (localize.drupal.org), you want them to be "default" translations AND you want them to overwrite what is there, since you want to take the most up to date greatness. Then once you launch your site, you might or might not want to take translation updates like that. If you value a well greased site setup, you might be shocked to get things change their name on the UI because the translation team decided now "account" should be translated differently. So you are more likely want to take new translations (ie. for new strings appearing in later core/contrib versions), but keep the old ones. So its more of a question, of where your site is in its lifetime, and how much of a control freak you are :)
The default assumes you are more of a control freak, so it applies best to production sites (where most sites would spend more of their times vs. in development). However, when in development, your more sensible defaults are likely to allow for changes as long as you get the latest great stuff IMHO.
Comment #89
Gábor HojtsyBTW however for custom translations, I think its more likely you want to overwrite everything by default, since you want to get your changes through no matter what. We don't currently default to that. We default to custom strings overwriting default translations but not your existing custom translations. (Which might again be a safer default for production sites, if you want to distribute your customizations among various sites but keep per-site customizations intact). So again, we default to protecting existing data except the default strings which you likely want to override anyway.
Now the real question is how does all this help us design a better UI for this? I'm not sure it would make sense to have an API for this in without a UI to affect it (i.e an import needs to know exactly what it is allowed to overwrite and remove), so it would be great to be able to move in a direction that is relatively comfortable at least. As @eigentor said, the D7 UI is also puzzling...
Comment #90
eigentor CreditAttribution: eigentor commentedO.K. this makes totally sense and should match 95% or more of users, and more importantly, the users that do not understand the system in depth.
So make this the default.
Now: should it be chosen by default and the options hidden behind an "options" fieldset or not.
- New users: would gain from that, because they do not need to worry and are not stopped by some fancy options that may make them hesitant and in consequence not import their .po file in fear of breaking something.
- Experienced Drupal users: would click the fieldset, find options, and as they are proficient problem-solvers (else they would never have sticked with Drupal that long) find an option that suits them, click that and are happy
- People that know the old UI and miss the two options to choose from: might go crazy, curse core developers, but in the end also click on the fieldset and find the options.
So that's what I would advocate for: make the option preselected that fits 80-95% of people importing a .po file and hide the confusing options behind a collapsible fieldset.
Comment #91
Gábor Hojtsy@eigentor: I think we agree that sane defaults make sense, however said sane defaults are different between the development state of the site vs. the deployed version as explained above. So if we hide them as advanced options it will be "bogus" by default for development (with current defaults).
Comment #92
Sutharsan CreditAttribution: Sutharsan commentedNo changes to import default settings yet.
Comment #93
eigentor CreditAttribution: eigentor commentedWell don't wanna play the broom invoked by the sorcerers apprentice that you cannot stop anymore :)
If you really wanna nail the UI I guess the only real way is some quick and dirty user testing. And find out who are the main users of this screen. Yeah, sane default is important.
Who does the screen target primarily? This question needs to be answered. I find we still make the mistake in Drupal to target ourselves that already know Drupal too much, when it comes to UI decisions.
So I'm mostly taking the side of the novice.
But if the novice never goes there, this makes for a completely different situation.
Comment #94
Gábor Hojtsy@eigentor: currently, this is the only UI/process we have for .po file imports in core. We want to build in l10n_update entirely, at which point this will be an advanced user UI only. So I think since we seem to be going in circles here now and my posts for translators at http://localize.drupal.org/node/4659 (syncdicated to planet) and on the translator mailing list did not result in complaints or any better ideas, we should proceed with this as we are and once we have the automated import in, then see if we need to have any adjustments (seems likely not). IMHO it would be better to focus on working on making this UI the advanced UI by building in the auto-import functionality, but we do need tracking of customized strings for the auto-import to be useful without killing your data, so we need to get over this to move forward.
What do people think about this?
Comment #95
Gábor HojtsyLooks very good to me. Only found one issue:
'system' should be LANGUAGE_SYSTEM.
Comment #96
Sutharsan CreditAttribution: Sutharsan commentedPatch modified with #95
Regarding the UI. I know this interface is difficult for Drupal newbies, I don't need a UX test for that. The best thing we can do for this user group is to prevent that they will need these pages in the first place. If they reach the import page, they have managed to downloaded a po file from l.d.o and want to import it into their site (and even reaching this point will be a challenge for them!). And that is exactly what Localization Update in core can help them with by its automatic imports from l.d.o. Even for experienced Drupal users this interface is challenging, but at lease we have a more limited set of scenarios to focus at. Lets get this issue rolling, it is a blocking issue for automated import.
Comment #98
Sutharsan CreditAttribution: Sutharsan commentedOk, try again ;)
Comment #99
Sutharsan CreditAttribution: Sutharsan commentedRemoved quotes from around LANGUAGE_SYSTEM.
Comment #100
Gábor HojtsyI think this looks good now.
Comment #101
andypostThis looks confusing, $customized is just a boolean.
Suppose doc-block should describe deeper what's going to be imported and overridden.
use array_filter() not array_sum()
use else to define $existing_customized, or just drop definition before if()
Also MAX() need docs!!! Why ? Do we have many translations for one string in one language?
seems empty() make more sense
This kind of arguments is hard to pass from code and harder to read
same
I think this logic should be refactored
Are you sure that it's easy to rememeber each of this params?
not_ not- - the underscore hard to remember!
This option really confusing let's hide it into fieldset
I think better make this fieldset with title Advanced options
This should be passed from form item, no reason for this logic here, use #return_value
content_options?
Advanced [export] options
this hard to read - better if() else
s/modified/customized
add description from schema here
not need extra braces
drupal 8 :)
can we re-use already implemented poFiles in tests?
Comment #102
Gábor Hojtsy@andypost: attached a patch with some of your notes fixed. Reponse one by one:
1. The customized status bit and the overwrite options are independently evaluated. I've extended / modified the descriptions a bit. Yes, $customized is just a boolean, just like $node->status, but we still have constants for it to have more readable code.
2. Ok, used count(array_filter()) instead of array_sum() > 0, not sure how is this an improvement.
3. Good catch on the MAX(), that seems like was an earlier misunderstanding by roderik on how plurals are implemented (they are not tied to the same lid). Removed the MAX() (and the note on plurals above).
4. !isset($existing_customized) is explicitly used to catch when there was no translation saved. empty() would kick in if the translation was not customized, in which case the db insert would fail. There is a comment there pointing this out, but I've extended the comment above $existing_customized too.
5. On the places where $existing_customized is used in a ternary operator, please suggest a better solution if you have one. Otherwise I think this looks pretty readable.
6. On the _locale_export_get_strings() options, this is a temporary solution and #1189184: OOP & PSR-0-ify gettext .po file parsing and generation is being actively worked on to refactor this whole thing. This makes most of our changes in the .po parsing code at all pretty temporary and I find it hard to justify any need to debate them much.
7. Please read the discussion above. We plan to introduce l10n_update functionality in core (if we have time beyond debating relatively minor code issues). At that point this screen will be likely *mainly* used for importing custom stuff or not used at all. So hiding the functionality that we anticipate most people would come to this screen for sounds pretty bad.
8. Same thing. Extensive discussions about that above.
9. I don't think checkboxes can have a #return_value for their unchecked state. Looks like not. So I don't see how would that solve this.
10. Yes, content_options. It is about what is the content of the exported file. If we call it "export_options" does it tell more? :)
11. Changed to an if/else although I don't think ternary operators are hard to read, they are used plenty in Drupal.
12. Explaining the customized field that it is about marking things that are customized sounds pretty funny. That is not an explanation at all. Modified that to be 'custom to this site' to make more sense.
13. Schema descriptions added to update.
14. Removed extra brace although I believe those enhanced readability :)
15. Changed all .po files to Drupal 8. Yes, there are quite a few .po files in the tests, but they test different things. At this point for example, we need to test both overwrites and new things, so we need some custom tailored .po files for that. You are welcome to open an issue for reworking those .po files in tests if you are interested.
I think this addresses all your concerns in different ways. I do hope we can get this in before 200 comments and maybe can work on something else for Drupal 8 too at some point.
Comment #104
Gábor HojtsyOf course if we remove MAX() the return value for the query is becoming different, so what about doing a more traditional object lookup and then checking its emptiness and customized property, which should separate the 'not there' vs. 'not customized' vs. 'there' tri-state.
Comment #105
andypostFixed another array_sum() - it's not good to sum booleans, also array_filter returns array and check for emptiness with count is overhead in function that used in loop is bad idea, I know about #1189184 but this is a really bottle-neck place
Also fixed another Drupal 6 in .po
1445004-opt-105.patch is a bit refactored to reduce a number of queries
Comment #107
andypostI've measured performance for array functions
Comment #108
andypostupdated to one query
Comment #109
Gábor HojtsyI think those changes look good. Should be back to RTBC then.
Comment #110
andypostSuppose we need measures on import with one and 2 queries, most of time system has string in both tables so initial import makes less sense. If one query has better statistics we could backport it to D7
Comment #111
Sutharsan CreditAttribution: Sutharsan commentedI have done performance tests with two scenario's on both patches:
The first scenario is with are strings which do not have a matching source string in the database. e.g. the intial import of a po file. The second scenario is importing string of with all strings have a matching source string in the database. e.g. import the same po file twice. In real live the initial import of a module will have a low overlap (estimated 0 - 20%) sequential imports of updated module updates and import of new module releases will have a high overlap (estimated 80 - 100%).
#108 is approx 5% slower than #107 on imports with 0% overlap
#108 is approx 15% faster than #107 on imports with 100% overlap
During the live time of a site many more imports will be carried out with a high translation overlap rate. Therefore I advise to use #108.
Comment #112
Sutharsan CreditAttribution: Sutharsan commentedForgot to mention, the above tests were carried out without overwriting existing translations. When overwriting existing translations both patches perform equal.
Comment #113
andypost@Sutharsan thanx a lot for testing! 5% slowness on initial import seems depends on mysql settings, less queries should be faster. In case of server on different machine boost should became bigger.
Comment #114
roderikSorry I'm late to the party :-p I didn't have anything to add to the higher level discussions but should have returned last week...
After a review of the thread I have some minor things (don't worry, you can set to RTBC in no time):
Note: The "Translation type" filter dropdown on the search screen still has options "Base translation" and "Customized translation". I didn't change "Base" back (despite inconsistency) because I really don't know if that would be any better.
Attached is the view of the import screen on a freshly installed site with no languages enabled and no translations imported. Right after importing your first .po file, one of the two now-hidden checkboxes will appear.
Comment #115
roderik...and I've left some other things for a followup issue on purpose, because IANAUIExpert. Feel free to ignore.
I realize that there is no way to explain the import screen fully to everyone without a full man page. But maybe a description with the checkboxes still helps to at least make inexperienced users not feel completely lost?
Or are descriptions that are this large, against UI rules? Probably, huh? (I'm not succeeding in making them any shorter.)
Also IMHO it doesn't hurt to make the first checkbox stand apart from the other two. Because now, users' first impression is "ah, there are 3 on/off options below each other, so 3 options of exactly the same type". Which isn't true. And the fact that the 2nd checkbox does not have a description, helps that.
Also, I see one other thing that might have fallen through the cracks: pixelite's #56 about making the first checkbox into radiobuttons with a Yes/No choice. That would also achieve 'making it stand apart from the other checkboxes'...
Anyway: The attached screenshot is all you need to decide whether you want to continue with #114 or #115.
Comment #116
Gábor HojtsyI'm starting to loosing faith that we ever going to have this in core. Looks like people have more fun debating how to do it then wanting to see it in. I think the hiding of checkboxes from your patch in #114 make sense, but these make no sense whatsoever:
This description used to be there but it was removed because it is trivial. Also, WTH include an empty option if that is not valid? What do you do if there is no language set? Is the form label not enough?
What do you do in the import if there is no language set? Which language do you import the translations to ?!?!
Comment #117
Gábor HojtsyFor the second patch, I think your finding on the search screen having wrong wording is spot on, that *should be* fixed. However, I'd prefer if we don't fiddle with this UI anymore, or we'll be in bikeshed land for another 3 weeks, which is likely lot of fun for some, but I'm more interested in delivering solutions for Drupal 8.
Can you please leave these two alone and open followups if you have concerns? Unless you want another 3 week bikeshed about this, that is. :/ :(
Comment #118
Gábor HojtsyIn other words, I'm posting the #118's comment. This is a clear WARNING sign, especially it is all in less than 2 months. We can clearly debate the UI indefinitely. We arrived at the conclusion that this is going to be an advanced UI once/if we reach the inclusion of l10n_update in core. If we keep debating this one, we lock our energies down here instead of working on more useful stuff. However, if we get the feature in with the current UI proposal, you can all be absolutely free to go back and debate the UI however long you want while others can work on actually building on this functionality and continuing the inclusion of l10n_update in core. If we don't get this patch in, we are locked in this debate and will not reach any useful goals anytime soon. Not good for anybody, unless you are looking for a meaty bikeshed. This issue was supposed to be simple and clearly not something that would take us two months to fix. If we fix such small issues with this pace, we can fix 3 more before Drupal 8 is frozen. Clear?
Comment #119
Sutharsan CreditAttribution: Sutharsan commentedI very much agree with Gábor and will therefore not comment on #114 - #117.
Filter select list modified to 'Non-customized translation' (other options unchanged: 'All' and 'Customized translation')
Patch based on #108 (1445004-opt-107.patch) as is was the better performing one.
Comment #120
roderikTo prevent an invasive action (creating a wrong language) from taking place if you didn't select anything.
You don't do anything in the import. You throw a validation error, that's what you do. Because of above.
Hey, I'm just answering your questions. As reference for the followup issue.
I'm sorry. I meant to only sweep through the last 50 comments to see how things have evolved, and meant to split out the 'trivial' stuff from the 'non trivial' stuff, that's why I created two patches. Apparently the notion of what is 'trivial' is something I should still get a hold of.
Reviewed Sutharsan's patch.
Comment #121
Gábor HojtsyThanks. Please let this get in and fiddle with the rest in followups. RTBC to commit can still easily be 1-2 weeks. :/
Comment #122
Dries CreditAttribution: Dries commentedThis is a great feature, and one that is much wanted I'm sure. Committed to 8.x.
I think it warrants a CHANGELOG.txt entry; let's add one?
Comment #123
Gábor HojtsyHere it is. Should be simple to get in.
Comment #124
Gábor Hojtsy(BTW added change notice node at http://drupal.org/node/1525160 too).
Comment #125
Dries CreditAttribution: Dries commentedMoving to Jennifer's queue.
Comment #126
jhodgdonLooks good -- changelog entry has been committed.
Comment #127
Gábor HojtsyThanks, off sprint then.