I’ve created a custom variable group which I want to store an int for object count and a LocalizedString for the object itself. This is how that currently looks:
[DisplayName("Object With Count")]
[Serializable]
public class ObjectWithCount : IVariableGroup, IVariable
{
public object GetSourceValue(ISelectorInfo _) => this;
public int count;
public LocalizedString objectName;
public bool TryGetValue(string key, out IVariable value)
{
switch (key)
{
case "count":
case "object-count":
value = new ReturnValue { SourceValue = count };
return true;
case "object":
value = new ReturnValue { SourceValue = objectName };
return true;
}
value = null;
return false;
}
}
struct ReturnValue : IVariable
{
public object SourceValue { get; set; }
public object GetSourceValue(ISelectorInfo _) => SourceValue;
}
The problem is that when I try to get the objectName value using smart strings, it just writes out the LocalizedString table and entry references. I’ve tried returning objectName.GetLocalizedString() instead but then I can’t access any metadata. Is there some specific class that I should be using instead of LocalizedString or is there any way around this?
The reason I’m doing this in the first place is that I’ve set up a bunch of smart string entries that automatically choose the right plural version of themselves using the variable ‘object-count.’ I need to be able to pass different object-counts to different objects but of course can’t have multiple local variables named ‘object-count.’ So this way I can pass in the ObjectWithCount variable as the source and it will get the count from there. I’d be very grateful if anyone knows a better way of doing this too.
Hi,
Is object-count supposed to be used in objectName or is it used in the main LocalizedString?
Maybe it would be simpler to use a nested LocalizedString with its own object-count variable instead?
Something like this
It still has its own object-count but its part of the localized string already.
In a way it’s both… Here’s a sample sentence to show what I mean:
“There are 10 animals. 4 of the animals are mammals and 1 mammal is a dog.”
So to make this sentence work dynamically, you need to be able to pass around object counts to different objects e.g. dog.object-count determines the plurality of the second instance of the mammal object, the dog object and whether to use is/are.
Using nested LocalizedString variables is possible but would be quite tedious and inefficient, especially if these sentences were to be expanded. I believe you can’t access the local variables of nested LocalizedStrings so you would need to have different ones for each combination of object and object count and an additional int variable for any dynamic plural stuff in the main string.
Ok. That’s going to be a tricky sentence to translate as the word order could change.
Yes, you can access them via script. The nested LocalizedString could be retrieved from the LocalizedString using the TryGetValue method. You would then cast the returned IVaribale to a LocalizedString and then do TryGetValue on that to get the counter variable.
Will the sentence always be in the form: “There are {animal-count} animals. {mammal-count} of the animals are mammals and {dog-count:plural: 1 mammal is a dog|{} mammals are dogs}”
or could it change based on the number of animals and types?
For example, could it become “There are 10 animals, 4 of the animals are mammals, 1 is a dog and 1 is a cat?”
Depending on how the sentence needs to be structured there are a few different ways to approach this. When we do this we want to consider the translator who may have to translate this in the future. Ideally, we want to try and keep it simple and avoid code that structures the sentence differently as it may not work for other languages.
So if we wanted to have a breakdown of the animals in a sentence we could create a List of LocalizedStrings, each with their count and animal type, we could then pass them into a single LocalizedString which could use a List formatter to separate them. When you put the localized strings into a list and pass that into the main LocalizedString.
It could then looks like this:
Main Sentence: “There are {animal-count} animals. {0:list:{}|, |, and }”
Number of dogs: “{count:plural: 1 mammal is a dog|{} mammals are dogs}”
Number of cats: “{count:plural: 1 mammal is a cat|{} mammals are cats}”
The code to put it all together could be something like this:
struct AnimalCount
{
public string animalName;
public int count;
}
public string GetLocalizedValue(List<AnimalCount> animals)
{
var rootString = new LocalizedString{ TableReference = "My Table", TableEntryReference = "Animals" };
// Create a list of all the animals and their counts.
var list = new List<string>();
foreach (var animal in animals)
{
var nestedString = new LocalizedString { TableReference = "My Table", TableEntryReference = animal.animalName };
// Add the count as a parameter.
nestedString.Add("count", new IntVariable { Value = animal.count });
list.Add(nestedString.GetLocalizedString());
}
rootString.Arguments = new[] { list };
return rootString.GetLocalizedString();
}
To go back to your original question, I think you should be able to get it working by returning objectName.GetSourceValue(selectorInfo) instead of objectName. LocalizedStrings need the source value when they are being used inside of other LocalizedStrings.