Repository: WeblateOrg/weblate

Issue:
Non-uppercase placeholders are not properly recognized
### Describe the issue

I use web extension JSON file format and use non-uppercase placeholders. It shows them in the placeholders section in uppercase, and doesn't highlight in the text:

![image](https://user-images.githubusercontent.com/39462442/170855164-5a9a8421-3fe0-4dcd-aa3f-5b596008979d.png)
![image](https://user-images.githubusercontent.com/39462442/170855171-e5c30023-2b09-4920-8b49-87c8b439acd6.png)

It starts highlighting if I change it to uppercase:

![image](https://user-images.githubusercontent.com/39462442/170855192-a0b6bd9f-c6b1-4e6c-a324-70d15ea1c455.png)

The string itself: https://hosted.weblate.org/translate/jump-cutter/extension-ui/en/?checksum=e358533698b9954c

### I already tried

- [X] I've read and searched [the documentation](https://docs.weblate.org/).
- [X] I've searched for similar issues in this repository.

### Steps to reproduce the behavior

_No response_

### Expected behavior

Placeholders in the "flags" section preserve source string casing.

### Screenshots

_No response_

### Exception traceback

_No response_

### How do you run Weblate?

weblate.org service

### Weblate versions

_No response_

### Weblate deploy checks

_No response_

### Additional context

_No response_


Discussion:
Placeholders are currently case-sensitive in Weblate.
Ok, but the placeholder appears in lower-case in the source string, but in flags it became uppercase.
It is extracted as uppercase because it is described that way in https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Internationalization#retrieving_message_strings_from_javascript.

It behaves this way since the beginning - eec96244458
Sounds like a bad practice, I don't think it should be followed.

I think we should look up how the placeholder is used in the source string (the `"message"` prop, not just "placeholders") and take casing from there.
I'll make an MR.
Also perhaps the same goes for ARB files? Everywhere I looked nobody really changes casing. But I don't know much about ARB.

https://github.com/WeblateOrg/weblate/blob/e21e8b22c5509c67a490eecc49b665c697a843a7/weblate/formats/ttkit.py#L913-L921

Examples:
https://phrase.com/blog/posts/flutter-localization/
https://localizely.com/flutter-arb/
The issue you have reported is now resolved. If you don’t feel it’s right, please follow its labels to get a clue for further steps.

* In case you see a similar problem, please open a separate issue.
* If you are happy with the outcome, don’t hesitate to support Weblate by making a [donation](https://weblate.org/donate/).
Should we maybe reopen this for ARB files? https://github.com/WeblateOrg/weblate/issues/7708#issuecomment-1141368868

Resolving patch:
diff --git a/weblate/formats/ttkit.py b/weblate/formats/ttkit.py
--- a/weblate/formats/ttkit.py
+++ b/weblate/formats/ttkit.py
@@ -898,7 +898,7 @@ def context(self):
         return context
 
 
-class WebExtensionJSONUnit(JSONUnit):
+class PlaceholdersJSONUnit(JSONUnit):
     @cached_property
     def flags(self):
         placeholders = self.mainunit.placeholders
@@ -918,19 +918,6 @@ def flags(self):
         return "placeholders:{}".format(":".join(placeholder_strings))
 
 
-class ARBJSONUnit(JSONUnit):
-    @cached_property
-    def flags(self):
-        placeholders = self.mainunit.placeholders
-        if not placeholders:
-            return ""
-        return "placeholders:{}".format(
-            ":".join(
-                Flags.format_value(f"{{{key.upper()}}}") for key in placeholders.keys()
-            )
-        )
-
-
 class CSVUnit(MonolingualSimpleUnit):
     @staticmethod
     def unescape_csv(string):
@@ -1440,7 +1427,7 @@ class WebExtensionJSONFormat(JSONFormat):
     loader = ("jsonl10n", "WebExtensionJsonFile")
     monolingual = True
     autoload = ("messages*.json",)
-    unit_class = WebExtensionJSONUnit
+    unit_class = PlaceholdersJSONUnit
 
 
 class I18NextFormat(JSONFormat):
@@ -1463,7 +1450,7 @@ class ARBFormat(JSONFormat):
     format_id = "arb"
     loader = ("jsonl10n", "ARBJsonFile")
     autoload = ("*.arb",)
-    unit_class = ARBJSONUnit
+    unit_class = PlaceholdersJSONUnit
     check_flags = ("icu-message-format",)
 
 


Test patch: