Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Localization support for any prototypes #4335

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

ficcialfaint
Copy link
Member

@ficcialfaint ficcialfaint commented Aug 30, 2023

About the PR

The PR adds ability to turn any prototype into localized prototype that supports localization in fluent file with custom prefix as entities do with ent- prefix.

How does it work?

There is now a new ILocalizedPrototype interface. You simply implement it in your prototype and add:

  • SetName -- the default name you set in the prototype, in YAML files
  • SetDesc -- same as SetName but for descriptions
  • Name -- the localized name
  • Description -- the localized description
  • CustomLocalizationPrefix - the prefix that will be used in .ftl files. For example, entities use ent- prefix: ent-BaseItem = base item
    Then you have to set Name's and Description's getters to ILocalizationManager.GetPrototypeData<YourPrototype>(ID).Description / .Name.

Here is a small example for a localized prototype:

[Prototype("construction")]
public sealed class ConstructionPrototype : IPrototype, ILocalizedPrototype, ISerializationHooks
{
    private ILocalizationManager _loc = default!;

    [DataField("name")]
    public string? SetName { get; private set; }

    [DataField("description")]
    public string? SetDesc { get; private set; }

    [ViewVariables]
    public string Name => _loc.GetPrototypeData<ConstructionPrototype>(ID).Name;

    [ViewVariables]
    public string Description => _loc.GetPrototypeData<ConstructionPrototype>(ID).Desc;

    public string CustomLocalizationPrefix { get; private set; } = "cnt"; // e.g. cnt-BaseCraft = cool name

    void ISerializationHooks.AfterDeserialization()
    {
        _loc = IoCManager.Resolve<ILocalizationManager>();
    }
}

Media


Copy link
Member

@ElectroJr ElectroJr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The given example is bad because it uses ISerializationHooks which are obsolete.
The localized strings should just get resolved once after prototypes have been (re)loaded, which would also mean you could just get rid of the caching dictionary.

string? name = null;
string? desc = null;

foreach (var prototype in _prototype.EnumerateParents(kind, prototypeId, true))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't recursively iterate up through a prototypes parents, this is just the direct parent list

if (!_prototype.TryIndex(kind, prototypeId, out var prototype))
return new PrototypeLocData("", "");

var lproto = (ILocalizedPrototype)prototype;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try cast

Comment on lines +39 to +45
[DataField("name")] public string? SetName { get; }

[DataField("description")] public string? SetDesc { get; }

[ViewVariables] public string Name { get; }

[ViewVariables] public string Description { get; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be wrong, but I don't think the data-field attributes do anything on interfaces?
I'm also not sure about whether VV works on interfaces.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, these should have documentation comments

@ficcialfaint
Copy link
Member Author

I just noticed the review, I'll see what I can do, thanks

{
// Concurrent dict so that multiple threads "reading" .Name won't cause a concurrent write issue
// when the cache gets populated.
private readonly ConcurrentDictionary<string, PrototypeLocData> _prototypeCache = new();
Copy link
Member

@ElectroJr ElectroJr Oct 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs to be per-prototype
NVM see my earlier comment, just remove it altogether.

Comment on lines +24 to +27
if (args.ByType.ContainsKey(typeof(EntityPrototype)))
FlushEntityCache();

FlushPrototypeCache();
Copy link
Member

@ElectroJr ElectroJr Oct 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should enumerate over kinds and only flush the cache for prototypes that actually changed.
Also FlushPrototypeCache() is broken, its just a copy paste of FlushEntityCache()

NVM see my earlier comment, just remove it altogether.

@LightVillet
Copy link

@ficcialfaint when

@Ygg01
Copy link
Contributor

Ygg01 commented Feb 3, 2024

This is probably too old to merge anymore. Close?

… into localized-prototypes

# Conflicts:
#	Robust.Shared/Localization/ILocalizationManager.cs
#	Robust.Shared/Localization/LocalizationManager.Entity.cs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants