<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://bugs.webkit.org/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.4.1"
          urlbase="https://bugs.webkit.org/"
          
          maintainer="admin@webkit.org"
>

    <bug>
          <bug_id>306492</bug_id>
          
          <creation_ts>2026-01-28 19:03:50 -0800</creation_ts>
          <short_desc>WebExtension i18n named placeholders fail when adjacent to non-space characters</short_desc>
          <delta_ts>2026-04-21 08:55:58 -0700</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>1</classification_id>
          <classification>Unclassified</classification>
          <product>WebKit</product>
          <component>WebKit Extensions</component>
          <version>WebKit Nightly Build</version>
          <rep_platform>Unspecified</rep_platform>
          <op_sys>Unspecified</op_sys>
          <bug_status>RESOLVED</bug_status>
          <resolution>FIXED</resolution>
          
          <see_also>https://bugs.webkit.org/show_bug.cgi?id=291956</see_also>
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords>InRadar</keywords>
          <priority>P2</priority>
          <bug_severity>Normal</bug_severity>
          <target_milestone>---</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter name="Brian Birtles">brian</reporter>
          <assigned_to name="Nobody">webkit-unassigned</assigned_to>
          <cc>ahmad.saleem792</cc>
    
    <cc>brian</cc>
    
    <cc>i.am.kanaru.sato</cc>
    
    <cc>timothy</cc>
    
    <cc>webkit-bug-importer</cc>
          

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>2176037</commentid>
    <comment_count>0</comment_count>
    <who name="Brian Birtles">brian</who>
    <bug_when>2026-01-28 19:03:50 -0800</bug_when>
    <thetext>Named placeholder substitution in WebExtensions localization (`i18n.getMessage`) fails when the placeholder is immediately preceded by a non-space character.

Example:

```
&quot;message&quot;: &quot;Data v$version$&quot;
```

does not substitute $version$, whereas:

```
&quot;message&quot;: &quot;Data v $version$&quot;
```

does.

This appears to be due to [this regex](https://github.com/WebKit/WebKit/blob/3a0d87473c4e6ed8a91d6a8df015cb777743f74f/Source/WebKit/Shared/Extensions/WebExtensionLocalization.cpp#L296):

```
auto localizableStringRegularExpression = JSC::Yarr::RegularExpression(&quot;(?:[^$]|^)(\\$([A-Za-z0-9_@]+)\\$)&quot;_s, { });
```

The way we use it is to look for the `index` and then, it the first character is a literal space, drop it:

```
        if (originalKey.startsWith(&apos; &apos;))
            originalKey = localizedString.substring(index + 1, matchLength - 1);
```

Previously (probably before converting to C++ in https://github.com/WebKit/WebKit/commit/944567bb72da80b8a98ac4aac76f70b700373989) it was possible to workaround this by using a U+200B character before the initial $, e.g. &quot;Data v\u200b$version$&quot; but that workaround no longer works.

This might seem like an edge case but for string in languages that don&apos;t use spaces to separate works (e.g. CJK languages) this comes up _everywhere_.

Chromium browsers and Gecko don&apos;t have this bug.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2176038</commentid>
    <comment_count>1</comment_count>
    <who name="Radar WebKit Bug Importer">webkit-bug-importer</who>
    <bug_when>2026-01-28 19:03:56 -0800</bug_when>
    <thetext>&lt;rdar://problem/169146196&gt;</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2176058</commentid>
    <comment_count>2</comment_count>
    <who name="Brian Birtles">brian</who>
    <bug_when>2026-01-28 21:08:20 -0800</bug_when>
    <thetext>Even worse, it has trouble with placeholders that are separated by only a single character and a space, e.g. &quot;$index$（ $volume$巻 $page$頁 ）&quot;

Due to [this line](https://github.com/WebKit/WebKit/blob/3a0d87473c4e6ed8a91d6a8df015cb777743f74f/Source/WebKit/Shared/Extensions/WebExtensionLocalization.cpp#L350):

```
        index += replacement.length() + 2;
```

It will start scanning _two_ characters after the replacement even though at this point we&apos;re dealing with positional arguments which only have _one_ dollar sign.

As a result, in the string &quot;$index$（ $volume$巻 $page$頁 ）&quot;, $index$ and $page$ will be replaced but $volume$ won&apos;t.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2176444</commentid>
    <comment_count>3</comment_count>
    <who name="Brian Birtles">brian</who>
    <bug_when>2026-01-29 21:22:11 -0800</bug_when>
    <thetext>&gt; It will start scanning _two_ characters after the replacement even though at this point we&apos;re dealing with positional arguments which only have _one_ dollar sign.

On further thought, I have no idea why it adds 2. I think 1 was to cover the first group in the regex, &quot;(?:[^$]|^)&quot; despite the fact that when matching at the start of the string that group will have length 0, but I&apos;ve no idea why it adds 2.

I&apos;d be glad to fix this up if it&apos;s possible to work on this without having access to a Mac and if someone can point me to where tests for this live.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2198160</commentid>
    <comment_count>4</comment_count>
    <who name="Kanaru Sato">i.am.kanaru.sato</who>
    <bug_when>2026-04-08 16:23:24 -0700</bug_when>
    <thetext>I&apos;d like to work on it :) Will submit a patch soon.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2198168</commentid>
    <comment_count>5</comment_count>
    <who name="Kanaru Sato">i.am.kanaru.sato</who>
    <bug_when>2026-04-08 16:35:53 -0700</bug_when>
    <thetext>submitted: https://github.com/WebKit/WebKit/pull/62313</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2202760</commentid>
    <comment_count>6</comment_count>
    <who name="Timothy Hatcher">timothy</who>
    <bug_when>2026-04-21 08:52:16 -0700</bug_when>
    <thetext>(In reply to Brian Birtles from comment #3)
&gt; &gt; It will start scanning _two_ characters after the replacement even though at this point we&apos;re dealing with positional arguments which only have _one_ dollar sign.
&gt; 
&gt; On further thought, I have no idea why it adds 2. I think 1 was to cover the
&gt; first group in the regex, &quot;(?:[^$]|^)&quot; despite the fact that when matching
&gt; at the start of the string that group will have length 0, but I&apos;ve no idea
&gt; why it adds 2.
&gt; 
&gt; I&apos;d be glad to fix this up if it&apos;s possible to work on this without having
&gt; access to a Mac and if someone can point me to where tests for this live.

The +2 was likely trying to account for the two dollar signs in `$name$` style matches, but positional uses `$N` (one dollar sign, no trailing). This caused the scanner to jump past the next positional placeholder when replacements were short — exactly the bug in comment #2.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2202763</commentid>
    <comment_count>7</comment_count>
    <who name="EWS">ews-feeder</who>
    <bug_when>2026-04-21 08:55:56 -0700</bug_when>
    <thetext>Committed 311685@main (bf4fcdebe481): &lt;https://commits.webkit.org/311685@main&gt;

Reviewed commits have been landed. Closing PR #62313 and removing active labels.</thetext>
  </long_desc>
      
      

    </bug>

</bugzilla>