-
Notifications
You must be signed in to change notification settings - Fork 14
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 #649
Localization #649
Conversation
That's a big PR! It'll take me some time to sift through it. I agree with your take that machine translation needs human review -- especially when we're talking about isolated words and phrases that may mean something particular in a musical/Finale context that the AI is unaware of. One question I have is about OS locale vs Finale language. According to this page, the only non-English languages that Finale comes in are French, German, Italian, Japanese, Dutch, Polish, and Swedish. I suspect that there are many users with a non-English locale who are running a version of Finale that doesn't match their locale. Will users want to see plugin dialogs in a language that doesn't match the rest of Finale? Is there any way to determine the language of the currently running Finale? (Probably not.) |
What a nice can of worms @asherber opened. I'll try to share what I know about it in a manner that is halfway coherent.
As part of testing my plugins originally and now testing Lua, I took the following steps.
As for how it all works, it matters which version of Finale you are running and which operating system.
There are other differences. The Spanish version uses the built-in OS folder-name translation. That is, all the default folder paths are the same between English Finale and Spanish Finale. The merely appear with different translations in the Finder. The German version, otoh, has hard-coded German folder names. I attribute this to the German version predating modern localization techniques. It's possible that the other Finale languages use yet different approaches. I haven't tried to test them. So now we get down to Aaron's key question:
There probably is no single answer to what users want. But I can say with certainty that what they actually see now is a hodge-podge mix of languages. I have always taken it is as given that if you have set a particular locale as your primary default locale, you should present that locale to them if you have it. But ymmv. |
Something else I'd like us to consider is, should we build in a standard way to extend the number of localizations? For example, a user might prefer to see the dialogs in Vietnamese, but there is no Vietnamese built into the script. We could conceivably modify the |
One thing that stands out to me is the use of the entire English phrase as the key for language strings in the examples, rather than a regular identifier. Although it might seem nice and readable, it's not good practice and it will introduce more difficulties in the long run, especially when the need arises to change the strings. Best to encourage good habits to start with. Some changes to the mixin library could be made to make the code less verbose but I'll think on it some more before I make some suggestions. |
For dealing with localised strings:
function methods:SetLocalizedText(key)
mixin_helper.assert_argument_type(2, key, "string", "FCString")
self:SetText(localization.localize(key))
end
function methods:AlertLocalizedError(message_key, title_key)
mixin_helper.assert_argument_type(2, message_key, "string", "FCString")
mixin_helper.assert_argument_type(3, title_key, "string", "FCString")
self:AlertError(localization.localize(message_key)), localization.localize(title_key))
end etc, etc |
@ThistleSifter I thought about building this into Taking that as given:
global_dialog:_FallbackCall("CreateChildUI", finenv.UI()):AlertError( --...
EDIT: |
Yes, the bundled scripts are big enough as it is. I guess it comes down to whether or not you want to enforce localisation as part of a coding style expectation in this repo. If all the scripts that use mixins also use the
Yes, because then the
|
If anyone is tracking this branch, I'm going to rebase it on upstream/master when I get the chance. |
1f26233
to
336a577
Compare
Okay, this is ready for more review and suggestions. Per comments from @asherber and @ThistleSifter I have made the following revisions:
Once I have signoff, I will merge it. I'm thinking I'll use squash and merge, because the long commit history is rather annoying. |
I'm not sure that this is a suitable option for our purposes. Take Do we actually need a general fallback other than
What about changing the signature of finenv.UI():AlertErrorLocalized(["input_error", "Some", "inserted text"], "error_title") |
Passing a table to If |
Lol, fwiw, Apple is definitely still recommending full text as keys. Check out the docs on string catalogs. I'm not saying we should fall back, though. Apple has way more support for sting catalogs than I am contemplating here. |
I don't have a strong feeling about fallback languages, and I find the discussion very interesting. I note that Finale itself is developed in English and then localized, and that keywords in Lua (along with almost every programming language) are in English; it doesn't seem unreasonable in the context of software for English to be the general fallback language, which I think is part of what @ThistleSifter is suggesting. What if name of the fallback file specified its locale (e.g., Base_en.lua)? Feel free to ignore if this isn't helpful; I admit that I haven't dealt with localization issues before. |
The language a language is developed in is irrelevant to how it should be localized. Finale is released with only a single localization and that localization is the language it's in. I have the Spanish and German versions on my computer, for example, and both of those (like the English version) have the one localization in But if @ThistleSifter is comfortable with EDIT: I said it was easy, but I'm not sure how to automatically |
Re |
I suppose there may be a way to pattern match in
That allows a script writer to specify a different fallback language if need be. |
Ah yes, I missed your reference to |
Out in the open source world, where people have to work together, snake case (sometimes other, but snake is the most popular esp. in the web languages) keys have been used for referencing translatable strings for well over 15 years. Organisations that can dictate terms because they have a functional monopoly can have some interesting policies, to put it gently. Not always bad, but it's often worth looking a little wider to see what everyone else is doing.
Yes, I like this idea. |
Yes, good catch. I have been thinking about this for the past couple of days because it would be nice to have and I think I have a solution for the error reporting but I have to work out how to do it. It might need to wait for the mixin rewrite because that has completely rewritten error handling with greater ease and flexibility for hooking in to it. |
Hold on, I've got it. I'll write it up and paste it here tomorrow. Edit: or maybe now. local function to_key_string(value)
if type(value) == "string" then
value = "\"" .. value .. "\""
end
return "[" .. tostring(value) .. "]"
end
function mixin_helper.process_string_arguments(self, method_func, ...)
for i = 1, select("#", ...) do
local v = select(i, ...)
mixin_helper.assert_argument_type(i + 1, v, "string", "number", "FCString", "FCStrings", "table")
if type(v) == "userdata" and v:ClassName() == "FCStrings" then
for str in each(v) do
method_func(self, str)
end
elseif type(v) == "table" then
for k2, v2 in pairsbykeys(v) do
mixin_helper.assert_argument_type(tostring(i + 1) .. to_key_string(k2), v2, "string", "number", "FCString")
method_func(self, v2)
end
else
method_func(self, v)
end
end
end |
* master: chore: autopublish 2024-02-07T20:57:40Z Update ties_remove_dangling.lua Update ties_remove_dangling.lua Update ties_remove_dangling.lua Update ties_remove_dangling.lua Update ties_remove_dangling.lua Update ties_remove_dangling.lua
I'll hold off checking in until seeing your brainstorm. How do you feel about adding to |
* master: chore: autopublish 2024-02-08T23:53:39Z Update FCMCtrlStatic.lua
I ended up editing in my brainstorm to the comment above last night. Here's a quick demo anyway: local t_num = {"this", "is", false, "a", "test"}
local t_str = {}
t_str.a = "this"
t_str.b = "is"
t_str.c = false
t_str.d = "a"
t_str.e = "test"
...
popup:AddStrings(t_num) -- bad argument #1[3] to 'AddStrings' ... etc
popup:AddStrings("foo", t_str) -- bad argument #2["c"] to 'AddStrings' ... etc
What about |
I am really puzzled by this statement as to how it is supposed to work:
I just tested it, and it passes a string to the first argument EDIT: Never mind. I guess the first argument is just used to identify the bad argument in the error message. (I read your followup message.) |
…that errors are reported at the correct level, rather than in `tryfunczzz`.
Technically it doesn't matter what you pass for the value of |
Okay, here it goes. I'm committing it. |
This PR introduces a mechanism for localization of scripts. It consists of the following:
library.localization
provides the run-time localization service that can be used everywhere except theplugindef
function.library.localization_developer
provides an API for auto-translating strings using OpenAI APIs.rgp-lua.md
describes a new feature where the user's OS-configured locale will now be passed to theplugindef
function starting in RGP Lua 0.71. This allowsplugindef
to localize strings while remaining dependency-free. The change is fully backwards compatible with all previous versions of RGP Lua and with JW Lua, provided you checklocale
for nil.auto_layout
is a demonstration script of auto-layout features coming in RGP Lua 0.71.auto_layout_localizing_script
shows how to uselibrary.localization_developer
to translate strings._FallbackCall
method to call any method that is new in 0.71.In developing this approach, I have come to realize that LLM translation is amazing, but it is not reliable enough to put in front of a user without human inspection and revision. I speak enough Spanish and German to be comfortable that the translations for transposition are usable. I do not feel the same way about the French, Chinese, Arabic, and Farsi that I put into the
auto_layout
sample. (Although a Farsi-speaking friend of mine said they are pretty good.) I mainly included Farsi and Arabic in the sample to confirm that right-to-left text works reasonably well.Unfortunately,
auto_layout
requires 0.71, but it is mainly a test of auto-layout features rather than localization per se.I welcome any and all suggestions. I have specifically added @ThistleSifter and @asherber as reviewers, but I welcome comments from anyone. I haven't marked it as a draft, but if there is enough conversation about the best way to make it work, I will so mark it. Localization adds complexity but it makes for a much better UX. That said, I would like to make the DX as smooth as possible.