Skip to content

Commit 5163e87

Browse files
author
Unity Technologies
committed
com.unity.localization@1.5.8
## [1.5.8] - 2025-09-26 ### Fixed - Fixed Smart Strings incorrectly evaluating global variables after the first selector. ([LOC-1252](https://issuetracker.unity3d.com/product/unity/issues/guid/LOC-1252)) - Simplified the string and asset picker so it does not include the side panels and customization options to match the object picker closer. - The string and asset picker will now remember the previous layout state. ([LOC-1256](https://issuetracker.unity3d.com/product/unity/issues/guid/LOC-1256))
1 parent cda93d6 commit 5163e87

40 files changed

+323
-114
lines changed

.attestation.p7m

0 Bytes
Binary file not shown.

.signature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"timestamp":1754559469,"signature":"H+irOWoDsX1XhY+YNnHoyvrfhcXWx8BGYP/X2ryelXBdUht9ofpy5h2+XUrKCJF/3SEU6erBCq0zyYlZh3luaBupd7H11GtTxGEOoSo6KFO9X2MvnDhmasmJIkLDPL72uDdvesOUiyBDMikoxI1Si/08GFmRl0HqcOX6zuuAMxtDmhVZ2QPNc7xcwiXkIBZ6jYSqkiedbdvo/PUBnhKtYoo0mh9LK25QqmF1bD7nnFe6gjRZrWlVBs/JhOCMAmCNCD+9WRASxxE+uj91L6djBTh97FbMTLNGcirQR01pobdWEmL07u/2KbYSbjiIEb15rox8gFMbuRMzGXTkiwUBNCb1vgNPkMSxlH6b9IBvG5WR5L7vwEAuUPtJm8PeFPkpnzVJi9kebVp9KoDylRUQqARBo+Dl7gLPkstCSvd14dWUn9y4c4x+CIzcJqEZ4skR6qOpkXIjwOa+uOVC6jOEWnZ1eD15tAX0zG7IlgV80MzQg/s888Wy+vstU91V9QEX","publicKey":"LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQm9qQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FZOEFNSUlCaWdLQ0FZRUFzdUhXYUhsZ0I1cVF4ZEJjTlJKSAordHR4SmoxcVY1NTdvMlZaRE1XaXhYRVBkRTBEMVFkT1JIRXNSS1RscmplUXlERU83ZlNQS0ZwZ1A3MU5TTnJCCkFHM2NFSU45aHNQVDhOVmllZmdWem5QTkVMenFkVmdEbFhpb2VpUnV6OERKWFgvblpmU1JWKytwbk9ySTRibG4KS0twelJlNW14OTc1SjhxZ1FvRktKT0NNRlpHdkJMR2MxSzZZaEIzOHJFODZCZzgzbUovWjBEYkVmQjBxZm13cgo2ZDVFUXFsd0E5Y3JZT1YyV1VpWXprSnBLNmJZNzRZNmM1TmpBcEFKeGNiaTFOaDlRVEhUcU44N0ZtMDF0R1ZwCjVNd1pXSWZuYVRUemEvTGZLelR5U0pka0tldEZMVGdkYXpMYlpzUEE2aHBSK0FJRTJhc0tLTi84UUk1N3UzU2cKL2xyMnZKS1IvU2l5eEN1Q20vQWJkYnJMbXk0WjlSdm1jMGdpclA4T0lLQWxBRWZ2TzV5Z2hSKy8vd1RpTFlzUQp1SllDM0V2UE16ZGdKUzdGR2FscnFLZzlPTCsxVzROY05yNWdveVdSUUJ0cktKaWlTZEJVWmVxb0RvSUY5NHpCCndGbzJJT1JFdXFqcU51M3diMWZIM3p1dGdtalFra3IxVjJhd3hmcExLWlROQWdNQkFBRT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg"}
1+
{"timestamp":1759161884,"signature":"QwaUGWQW7VE2okGWrdkLWxh4+4XU+Io//8XmWJNzB51axuyY/JNOGEZ5Nd3M4mUy2OOI5KkeJ6mpJClocLgITgmOpeIA49nsamwxNBYJr4RKV05wEaQWMnm+vmaULrzVW/nNmoeQddKNGBRfHI+Uer3fwSvHGSW8ypQZaDjEMQrs+nEvf3cqjD6jJcH+zBmOzTWQgJHiRQ3N3Asr7+SIcCgmxbsWQoN2Tlc4uGy/x6Th6qAwuWU++RgUht4AOQr31yZvI016KwiswHuikY8D3lHSBsGNlMmulXEk2RDejGfck3R7EjveX5toJVMcHfsY60Vvw5eVH2hbPAGhfWJAdvNojtDIupvkZpb03oqT/jeCSW2wlTkmw6ruQyoynxvGzCqv7CyXe8CvQ2aPUVxR5OvwX5Ltm2Bh+9r3++mxrHuX2onfXr5rGJzx3ISHdojDiTdwv/uiJY4IrObNAl24Eac7TEqffhOiOMvV6jrg38vQNk5Gkb79teJfmaaM1e5a","publicKey":"LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQm9qQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FZOEFNSUlCaWdLQ0FZRUFzdUhXYUhsZ0I1cVF4ZEJjTlJKSAordHR4SmoxcVY1NTdvMlZaRE1XaXhYRVBkRTBEMVFkT1JIRXNSS1RscmplUXlERU83ZlNQS0ZwZ1A3MU5TTnJCCkFHM2NFSU45aHNQVDhOVmllZmdWem5QTkVMenFkVmdEbFhpb2VpUnV6OERKWFgvblpmU1JWKytwbk9ySTRibG4KS0twelJlNW14OTc1SjhxZ1FvRktKT0NNRlpHdkJMR2MxSzZZaEIzOHJFODZCZzgzbUovWjBEYkVmQjBxZm13cgo2ZDVFUXFsd0E5Y3JZT1YyV1VpWXprSnBLNmJZNzRZNmM1TmpBcEFKeGNiaTFOaDlRVEhUcU44N0ZtMDF0R1ZwCjVNd1pXSWZuYVRUemEvTGZLelR5U0pka0tldEZMVGdkYXpMYlpzUEE2aHBSK0FJRTJhc0tLTi84UUk1N3UzU2cKL2xyMnZKS1IvU2l5eEN1Q20vQWJkYnJMbXk0WjlSdm1jMGdpclA4T0lLQWxBRWZ2TzV5Z2hSKy8vd1RpTFlzUQp1SllDM0V2UE16ZGdKUzdGR2FscnFLZzlPTCsxVzROY05yNWdveVdSUUJ0cktKaWlTZEJVWmVxb0RvSUY5NHpCCndGbzJJT1JFdXFqcU51M3diMWZIM3p1dGdtalFra3IxVjJhd3hmcExLWlROQWdNQkFBRT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg"}

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
All notable changes to this package will be documented in this file.
44

5+
## [1.5.8] - 2025-09-26
6+
7+
### Fixed
8+
9+
- Fixed Smart Strings incorrectly evaluating global variables after the first selector. ([LOC-1252](https://issuetracker.unity3d.com/product/unity/issues/guid/LOC-1252))
10+
- Simplified the string and asset picker so it does not include the side panels and customization options to match the object picker closer.
11+
- The string and asset picker will now remember the previous layout state. ([LOC-1256](https://issuetracker.unity3d.com/product/unity/issues/guid/LOC-1256))
12+
513
## [1.5.7] - 2025-08-07
614

715
### Fixed

DocCodeSamples.Tests/SmartStringSamples.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
using UnityEditor.Localization;
55
using UnityEngine;
66
using UnityEngine.Localization;
7-
using UnityEngine.Localization.SmartFormat.Core.Extensions;
87
using UnityEngine.Localization.Tables;
9-
using Random = UnityEngine.Random;
108

119
public class SmartStringSamples
1210
{
@@ -304,6 +302,19 @@ public static void PluralFormatterArguments()
304302
new[] { "Mohamed" }
305303
#endregion
306304
};
305+
306+
#region plural-custom-formatter
307+
UnityEngine.Localization.SmartFormat.Utilities.PluralRules.IsoLangToDelegate.Add("ru-custom", (val, count) =>
308+
{
309+
// evaluate normal Russian rules
310+
var rule = UnityEngine.Localization.SmartFormat.Utilities.PluralRules.IsoLangToDelegate["ru"];
311+
var index = rule(val, count);
312+
313+
// Add your fallback here.
314+
// Clamp it to our expected index to prevent the exception.
315+
return Mathf.Clamp(index, 0, 1);
316+
});
317+
#endregion
307318
}
308319

309320
public static void SubStringFormatterArgument()

Documentation~/Smart/Conditional-Formatter.md

Lines changed: 116 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,45 @@
33
Conditional formatting occurs on any placeholder that contains a pipe character `|` after the colon `:`.
44
To invoke the [Conditional Formatter](xref:UnityEngine.Localization.SmartFormat.Extensions.ConditionalFormatter) explicitly use the name "conditional" or "cond". It can also be used implicitly when no name is provided.
55

6-
| **Data Type** | **Syntax** | **Example** |
7-
| ------------- | ---------- | ----------- |
8-
| **Number (Integer, Double, etc...)** | {0:one\|default} | {0} {0:item\|items} |
9-
| | {0} {0:item\|items} | {0:no items\|one item\|many items} |
10-
| | {0:negative\|zero\|one\|default} | {0:negative items\|no items\|one item\|many items}
11-
| **bool** | {0:true\|false} | Enabled? {0:Yes\|No} |
12-
| **string** | {0:default\|null or empty} | Text: {0:{0}\|No text to display}
13-
| **DateTime** | {0:before\|after} (as compared to Date.Now) | My birthday {0:was on\|will be on} {0:MMMM d} |
14-
| **TimeSpan** | {0:negative\|positive} | My birthday {0:was {0} ago\|will be in {0} from now} |
15-
| | {0:negative\|zero\|positive} | My birthday {0:was {0} ago\|is today!\|will be in {0} from now} |
16-
| **object** | {0:default\|nothing} | Property: {0:{0}\|(Nothing)} |
6+
The behavior of Conditional Formatter varies depending on the data type of the placeholder:
7+
8+
## Number
9+
10+
When you use a number type, such as integer or double, the value determines which item is selected from the choices list. If the value is not an integer, it is rounded down to the nearest whole number—the floor value is used as the index.
11+
12+
If the value is negative or exceeds the number of available choices, the default option is returned.
13+
14+
The following shows the example outputs of the number type:
15+
16+
| **Syntax** | **Value** | **Output** |
17+
| ----------- | --------- | ---------- |
18+
| {0:cond:Apple\|Pie\|Orange\|Banana\|No fruit} | 0 | "Apple" |
19+
| {0:cond:Apple\|Pie\|Orange\|Banana\|No fruit} | 3 | "Banana" |
20+
| {0:cond:Apple\|Pie\|Orange\|Banana\|No fruit} | -1 | "No Fruit" |
21+
| {value:cond:zero\|one\|two\|three\|other} | 0 | "zero" |
22+
| {value:cond:zero\|one\|two\|three\|other} | 1 | "one" |
23+
| {value:cond:zero\|one\|two\|three\|other} | 4 | "other" |
24+
25+
### Complex Comparisons
26+
27+
You can define more complex comparisons with the following syntax:
28+
29+
- Each parameter is separated by a `|`.
30+
- A comparison is followed by a ?, then the corresponding output text.
31+
- The final (default) entry does not include a comparison or a ?; it serves as the fallback if no conditions are met.
1732

1833
Each parameter is separated by `|`. The comparison is followed by a `?` and then the text. The last (default) entry does not contain a comparison nor a `?`.
1934

2035
The following comparisons are supported:
2136

22-
- **>=**
23-
- **>**
24-
- **=**
25-
- **<**
26-
- **<=**
27-
- **!=**
37+
| **Operator** | **Description** |
38+
| ------------ | ----------- |
39+
| **>=** | greater than or equal to |
40+
| **>** | greater than |
41+
| **=** | equal to |
42+
| **<** | less than |
43+
| **<=** | less than or equal to |
44+
| **!=** | not equal to |
2845

2946
To combine comparisons, use `&` for AND or `/` for OR.
3047

@@ -51,3 +68,85 @@ To combine comparisons, use `&` for AND or `/` for OR.
5168
</tr>
5269

5370
</table>
71+
72+
## Booleans
73+
74+
When you use a boolean data type, the value determines the output.
75+
If the value is true, the first item in the output choices is used. If the value is false, the second item is selected.
76+
77+
Syntax: `{0:cond:true|false}`.
78+
79+
| **Syntax** | **Value** | **Output** |
80+
| ---------- | --------- | ---------- |
81+
| Enabled? {0:Yes\|No}. | true | "Enabled? Yes." |
82+
| Enabled? {0:Yes\|No}. | false | "Enabled? No." |
83+
84+
## Strings
85+
86+
When you use a string data type, the value itself is output as long as it is not null or an empty string (""). If the value is null or empty, the default choice is used instead.
87+
88+
Syntax: `{0:cond:default|null or empty}`
89+
90+
| **Syntax** | **Value** | **Output** |
91+
| ---------- | --------- | ---------- |
92+
| The string is {0:not null or empty|null or empty} | "Some text" | "The string is not null or empty" |
93+
| The string is {0:not null or empty|null or empty} | "" | "The string is null or empty" |
94+
| Text: {0:{0}\|No text to display} | "Hello World" | "Text: Hello World" |
95+
| Text: {0:{0}\|No text to display} | null | "No text to display" |
96+
| Text: {0:{0}\|No text to display} | "" | "No text to display" |
97+
98+
## DateTime or DateTimeOffset
99+
100+
When you use DateTime or DateTimeOffset data types, the value is compared to the **current calendar date** (year, month, and day only).
101+
102+
If there are three output choices, the index values are:
103+
104+
- 0 for a past date
105+
- 1 for today
106+
- 2 for a future date
107+
108+
Syntax: `{0:cond:past date|today|future date}`
109+
110+
If there are two output choices, the index values are:
111+
112+
- 0 for today or a past date
113+
- 1 for a future date
114+
115+
Syntax: `{0:cond:today or past date|future date}`
116+
117+
| **Syntax** | **Value** | **Output** |
118+
| ---------- | --------- | ---------- |
119+
| My birthday {0:was yesterday\|is today\|will be tomorrow} | DateTime.Now.AddDays(1) | "My birthday was yesterday" |
120+
| My birthday {0:was yesterday\|is today\|will be tomorrow} | DateTime.Now | "My birthday is today" |
121+
| My birthday {0:was yesterday\|is today\|will be tomorrow} | DateTime.Now.AddDays(-1) | "My birthday will be tomorrow" |
122+
123+
## TimeSpan
124+
125+
When using the TimeSpan data type, the value is compared to `TimeSpan.Zero`.
126+
127+
If there are three output choices, the index values are:
128+
129+
- 0 for a negative duration
130+
- 1 for zero
131+
- 2 for a positive duration
132+
133+
Syntax: `{0:cond:negative duration|zero|positive duration}`
134+
135+
If there are two output choices, the index values are:
136+
137+
- 0 for a negative or zero duration
138+
- 1 for a positive duration
139+
140+
Syntax: `{0:cond:negative or zero duration|positive duration}`
141+
142+
| **Syntax** | **Value** | **Output** |
143+
| ---------- | --------- | ---------- |
144+
| The event {0:cond:will start in {Hours} hours\|is now\|was {Hours} hours ago} | TimeSpan.Zero.Add(new TimeSpan(-2,0,0)) | "The event will start in 2 hours" |
145+
| The event {0:cond:will start in {Hours} hours\|is now\|was {Hours} hours ago} | TimeSpan.Zero | "The event is now" |
146+
| The event {0:cond:will start in {Hours} hours\|is now\|was {Hours} hours ago} | TimeSpan.Zero.Add(new TimeSpan(3,0,0)) | "The event was 3 hours ago" |
147+
148+
## Other (object)
149+
150+
If the data type is not one of the types listed above, it is treated as a general object and evaluated against null. If the value is not null, the choice at index 0 is used. If the value is null, the choice at index 1 is used instead.
151+
152+
Syntax: `{0:cond:not null|null}`

Documentation~/Smart/Plural-Formatter.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,15 @@ To determine which plural rules to apply, the Plural Localization Formatter uses
6868
</tr>
6969

7070
</table>
71+
72+
## Custom plural rules
73+
74+
You can add custom plural rules to replace existing ones or create new rules. Sometimes, you might want to use a custom ruleset for particular situations without changing the default rules everywhere. To do this, define a new plural rule and reference it directly in your smart string with brackets.
75+
76+
The following example defines a custom plural rule for Russian that uses two plural forms instead of the standard three. When the pluralization logic requires the third form, this rule redirects it to the second form. This provides more precise control in scenarios where only two plural variations are needed.
77+
78+
[!code-cs[](../../DocCodeSamples.Tests/SmartStringSamples.cs#plural-custom-formatter)]
79+
80+
Example: `Жемчужин{count:p(ru-custom):а|ы|}`
81+
82+
Note that the custom plural rule is invoked by placing `ru-custom` inside the brackets.

Editor/EditorAddressablesInterface.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ public InMemoryResourceLocation(string name, string id, string providerId, Type
2929
readonly ResourceManager m_ResourceManager = new ResourceManager();
3030

3131
// Addressables is only safe to use in playmode, any other time we use the asset database. (LOC-722)
32-
internal bool UseAddressables => (LocalizationSettings.Instance.IsPlayingOverride.HasValue && LocalizationSettings.Instance.IsPlayingOverride.Value) ||
33-
(LocalizationSettings.Instance.IsPlayingOrWillChangePlaymode && PlayModeState == PlayModeStateChange.EnteredPlayMode);
32+
internal bool UseAddressables => (PlaymodeState.IsPlayingOverride.HasValue && PlaymodeState.IsPlayingOverride.Value) ||
33+
(PlaymodeState.IsPlayingOrWillChangePlaymode && PlayModeState == PlayModeStateChange.EnteredPlayMode);
3434

3535
internal static PlayModeStateChange PlayModeState => EditorApplication.isPlaying ?
3636
EditorApplication.isPlayingOrWillChangePlaymode ? PlayModeStateChange.EnteredPlayMode : PlayModeStateChange.ExitingPlayMode :
@@ -50,7 +50,7 @@ static TObject LoadAsset<TObject>(string address) where TObject : class
5050

5151
internal override AsyncOperationHandle<IList<IResourceLocation>> LoadResourceLocationsWithLabelsAsyncInternal(IEnumerable labels, MergeMode mode, Type type = null)
5252
{
53-
if (LocalizationSettings.Instance.IsPlayingOrWillChangePlaymode)
53+
if (PlaymodeState.IsPlayingOrWillChangePlaymode)
5454
return base.LoadResourceLocationsWithLabelsAsyncInternal(labels, mode, type);
5555

5656
throw new NotImplementedException("Should not be called outside of play mode");
@@ -92,7 +92,7 @@ internal override AsyncOperationHandle<IList<IResourceLocation>> LoadTableLocati
9292

9393
internal override AsyncOperationHandle<IList<TObject>> LoadAssetsFromLocationsInternal<TObject>(IList<IResourceLocation> locations, Action<TObject> callback)
9494
{
95-
if (LocalizationSettings.Instance.IsPlayingOrWillChangePlaymode)
95+
if (PlaymodeState.IsPlayingOrWillChangePlaymode)
9696
return base.LoadAssetsFromLocationsInternal(locations, callback);
9797

9898
throw new NotImplementedException("Should not be called outside of play mode");
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace UnityEditor.Localization.Bridge
2+
{
3+
static class InspectorWindowBridge
4+
{
5+
public static void Repaint()
6+
{
7+
// This is used to repaint the inspector window when the selection changes.
8+
// It is used by the LocalizedReferencePicker to ensure the inspector updates
9+
// when a new reference is selected.
10+
InspectorWindow.RepaintAllInspectors();
11+
}
12+
}
13+
}

Editor/InternalBridge/InspectorWindowBridge.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Editor/Platform/iOS/BuildPlayerIOS.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// The PBX classes used here are part of the Mac player, which is
2+
// often missing in test environments. This code is excluded from test builds
3+
// to avoid compilation failures on CI.
4+
#if !UNITY_INCLUDE_TESTS
5+
16
#if ((UNITY_TVOS || UNITY_STANDALONE_OSX || UNITY_VISIONOS) && ENABLE_LOCALIZATION_XCODE_SUPPORT) || (UNITY_IOS || UNITY_IPHONE)
27
using UnityEditor.Build;
38
using UnityEditor.Build.Reporting;
@@ -86,3 +91,4 @@ static void ClearPlayerSettingsDirtyFlag()
8691
}
8792
}
8893
#endif
94+
#endif

0 commit comments

Comments
 (0)