1. I got spoiled by AceLocale-3.0, but now I no longer have that luxury, as I am writing Rift addons. The good news is that the Rift API isn't that different from pure Lua. Rift even has the local MyAddon, Data = ...

    To that end, the methods suggested in your book, this site's code snippets, and this wiki all will work with no changes. Other than replacing GetLocale() with Inspect.System.Language() that is.

    However, the intent of the above assumes for the most part that your translations are in the core addon file. I would like to have the translations in separate files, English.lua, French.lua, etc. I know I need to load the default language first, which is English.lua, in my toc, but it would be great to return out if the language doesn't match the client.

    **Edit: It occurs to me just how spoiled I had become. I am looking at the snippets and the wiki, and I don't know what to put where between core.lua, English.lua, and French.lua

    Suggestions?

    I got spoiled by AceLocale-3.0, but now I no longer have that luxury, as I am writing Rift addons. The good news is that the Rift API isn't that different from pure Lua. Rift even has the local MyAddon, Data = ...

    But AceLocale didn't do... anything. boggle

    To that end, the methods suggested in your book, this site's code snippets, and this wiki all will work with no changes. Other than replacing GetLocale() with Inspect.System.Language() that is.

    However, the intent of the above assumes for the most part that your translations are in the core addon file. I would like to have the translations in separate files, English.lua, French.lua, etc. I know I need to load the default language first, which is English.lua, in my toc, but it would be great to return out if the language doesn't match the client.

    **Edit: It occurs to me just how spoiled I had become. I am looking at the snippets and the wiki, and I don't know what to put where between core.lua, English.lua, and French.lua

    You can do it however you want, the fact that you used AceLocale just hid the details (which are really simple) from you. I don't use the wiki version, I think this is all too bizarrely complicated.

    Here's the code from my AddonCore.lua, which I use in most addons, where addon is the table passed in by the engine.

     --[[-------------------------------------------------------------------------
     --  Localization
     -------------------------------------------------------------------------]]--
    
     addon.L = addon.L or setmetatable({}, {
         __index = function(t, k)
             rawset(t, k, k)
             return k
         end,
         __newindex = function(t, k, v)
             if v == true then
                 rawset(t, k, k)
             else
                 rawset(t, k, v)
             end
         end,
     })
    
     function addon:RegisterLocale(locale, tbl)
         if locale == "enUS" or locale == GetLocale() then
             for k,v in pairs(tbl) do
                 if v == true then
                     self.L[k] = k
                 elseif type(v) == "string" then
                     self.L[k] = v
                 else
                     self.L[k] = k
                 end
             end
         end
     end
    

    The first just sets up a locale table with a metatable. This metatable just spits back whatever its given if it doesn't have a translation for it. This means that addon.L["The monkey flings his poo"] just returns the string "The monkey flings his poo", unless there is a translation.

    This file is loaded first, before my main addon file so everything is set up. Then I load Localization.enUS.lua which contains the following:

     local translations = {
       ["some string"] = "some string",
     }
    
     addon:RegisterLocale("enUS", translations)
     translations = nil
    

    I do the same for any others, such as Localization.deDE.lua:

     local translations = {
       ["The girl drinks milk"] = "Das Mädchen trinkt Milch",
     }
    
     addon:RegisterLocale("deDE", translations)
     translations = nil
    

    It's pretty straightforward!

    But AceLocale didn't do... anything. boggle

    It didn't? Then what does it do?

    Here's the code from my AddonCore.lua, which I use in most addons, where addon is the table passed in by the engine.

    local addon, table = ... Alright, and if I wanted a local L variable, would I put that at the end of the following code, or right after the addon table?

     --[[-------------------------------------------------------------------------
     --  Localization
     -------------------------------------------------------------------------]]--
     
     addon.L = addon.L or setmetatable({}, {
         __index = function(t, k)
             rawset(t, k, k)
             return k
         end,
         __newindex = function(t, k, v)
             if v == true then
                 rawset(t, k, k)
             else
                 rawset(t, k, v)
             end
         end,
     })
     
     function addon:RegisterLocale(locale, tbl)
         if locale == "English" or locale == Inspect.System.Language() then -- Rift change
             for k,v in pairs(tbl) do
                 if v == true then
                     self.L[k] = k
                 elseif type(v) == "string" then
                     self.L[k] = v
                 else
                     self.L[k] = k
                 end
             end
         end
     end
    

    The first just sets up a locale table with a metatable. This metatable just spits back whatever its given if it doesn't have a translation for it. This means that addon.L["The monkey flings his poo"] just returns the string "The monkey flings his poo", unless there is a translation.

    Perfect!

    This file is loaded first, before my main addon file so everything is set up. Then I load Localization.enUS.lua which contains the following:

    Wait, you lost me. I was fine up til now. Does mean you have three files? AddonCore.lua with the above code, then core.lua with your actual addon code, and then localization files?

     local translations = {
       ["some string"] = "some string",
     }
     
     addon:RegisterLocale("enUS", translations)
     translations = nil
    

    I do the same for any others, such as Localization.deDE.lua:

     local translations = {
       ["The girl drinks milk"] = "Das Mädchen trinkt Milch",
     }
    
     addon:RegisterLocale("deDE", translations)
     translations = nil
    

    It's pretty straightforward!

    But AceLocale didn't do... anything. boggle

    It didn't? Then what does it do?

    It was basically a whole bunch of code that made localization earlier and harder at the same time. Easier because it hid the 4 lines of code you needed, and harder because it hid those details from you 100%.

    Here's the code from my AddonCore.lua, which I use in most addons, where addon is the table passed in by the engine.

    local addon, table = ... Alright, and if I wanted a local L variable, would I put that at the end of the following code, or right after the addon table?

     --[[-------------------------------------------------------------------------
     --  Localization
     -------------------------------------------------------------------------]]--
     
     addon.L = addon.L or setmetatable({}, {
         __index = function(t, k)
             rawset(t, k, k)
             return k
         end,
         __newindex = function(t, k, v)
             if v == true then
                 rawset(t, k, k)
             else
                 rawset(t, k, v)
             end
         end,
     })
     
     function addon:RegisterLocale(locale, tbl)
         if locale == "English" or locale == Inspect.System.Language() then -- Rift change
             for k,v in pairs(tbl) do
                 if v == true then
                     self.L[k] = k
                 elseif type(v) == "string" then
                     self.L[k] = v
                 else
                     self.L[k] = k
                 end
             end
         end
     end
    

    The first just sets up a locale table with a metatable. This metatable just spits back whatever its given if it doesn't have a translation for it. This means that addon.L["The monkey flings his poo"] just returns the string "The monkey flings his poo", unless there is a translation.

    Perfect!

    This file is loaded first, before my main addon file so everything is set up. Then I load Localization.enUS.lua which contains the following:

    Wait, you lost me. I was fine up til now. Does mean you have three files? AddonCore.lua with the above code, then core.lua with your actual addon code, and then localization files?

    I don't use core.lua I hate the name core.lua, but that's another story. But yes, I have several files and they are loaded in this order:

    AddonCore.lua Localization.enUS.lua Localization.deDE.lua Clique.lua

     local translations = {
       ["some string"] = "some string",
     }
     
     addon:RegisterLocale("enUS", translations)
     translations = nil
    

    I do the same for any others, such as Localization.deDE.lua:

     local translations = {
       ["The girl drinks milk"] = "Das Mädchen trinkt Milch",
     }
    
     addon:RegisterLocale("deDE", translations)
     translations = nil
    

    It's pretty straightforward!

    Excellent, and thank you! And I figured out where to put the local L = addon.L -- at the top of the main addon file, or Clique.lua, in this case. Once that is done, then Print(L["some string"]) will work fine.

    Once again, thank you for the help.

    ** Edit: LOL, forgot the L in the print statement!

    Mr Whitehead, sorry for dredging this up, but I was wondering what it would take for modifications to make this code standalone? Load once, every addon that uses it works with no conflicts or weird translation duplication. Yes, turn it into a library.

    The existing code works great because the meta table is using the private addon table, but I can't do that if I convert to a lib. Is it as simple as assigning its own name to the meta and function, or is there more work? For lack of a better name, I recycled AceLocale for my example. I did notice the original AceLocale-3.0 takes the addon name as a parameter in its registration function. I can do that easily enough. I also think I can validate both the registered locale and the addon.

     local AceLocale = {} -- local reference for speed
     _G.AceLocale = AceLocale -- global reference because it is a library file
    
     -- create meta table and get it ready for unknown quantity of tranlations
     AceLocale = AceLocale or setmetatable({}, {
        __index = function(t, k)
            rawset(t, k, k)
            return k
        end,
        __newindex = function(t, k, v)
            if v == true then
                rawset(t, k, k)
            else
                rawset(t, k, v)
            end
        end,
     })
    
    
     function AceLocale:RegisterLocale(locale, tbl)
        if locale == "English" or locale == Inspect.System.Language() then
            for k,v in pairs(tbl) do
                if v == true then
                    self.L[k] = k
                elseif type(v) == "string" then
                    self.L[k] = v
                else
                    self.L[k] = k
                end
            end
        end
     end
    

    I really do not understand your question. There are already locale libraries (AceLocale) if you want something that is a shared library, but as I've shown there's no reason or need to do that.

    If you want to make some code a library, you can look at the documentation for LibStub, which is the way that 99% of all libraries register themselves as globally available.