From dac4415699464264c43ac7e46ed23e45f73bf21e Mon Sep 17 00:00:00 2001 From: Benjamin Winger Date: Tue, 12 Apr 2022 13:09:53 -0400 Subject: [PATCH 1/2] Moved localisation docs to dedicated page --- docs/source/reference/modding/index.rst | 1 + .../source/reference/modding/localisation.rst | 83 +++++++++++++++++++ files/lua_api/openmw/core.lua | 45 ++-------- 3 files changed, 92 insertions(+), 37 deletions(-) create mode 100644 docs/source/reference/modding/localisation.rst diff --git a/docs/source/reference/modding/index.rst b/docs/source/reference/modding/index.rst index 440db96d8c..1e8560930a 100644 --- a/docs/source/reference/modding/index.rst +++ b/docs/source/reference/modding/index.rst @@ -28,3 +28,4 @@ about creating new content for OpenMW, please refer to sky-system extended paths + localisation diff --git a/docs/source/reference/modding/localisation.rst b/docs/source/reference/modding/localisation.rst new file mode 100644 index 0000000000..c0bf766d66 --- /dev/null +++ b/docs/source/reference/modding/localisation.rst @@ -0,0 +1,83 @@ +Localisation +============ + +OpenMW supports localisation of mods using ICU MessageFormat wrapped in YAML. +Currently this is only possible using the +`openmw.core.l10n <../lua-scripting/openmw_core.html##(core).l10n>`_ lua function. + +Locales +------- + +Locales usually have the form ``{lang}_{COUNTRY}``, +where ``{lang}`` is a lowercase two-letter language code and ``{COUNTRY}`` is an uppercase +two-letter country code. Localisation files *must* have this exact capitalisation and separator +to be recognized. + +When users request a locale using the :ref:`preferred locales` setting they do not need to match capitalisation +and can also use hyphens instead of underscores. The locale will be normalised to the above format. + +Locales may also contain variants and keywords, though these usually will not be necessary. +See `The Locale chapter of the ICU Guide `_ for full details. + +Localisation Files +-------------------------- + +Localisation files (containing the message names and translations) should be stored in the +VFS as files of the form ``l10n//.yaml``. + +Messages contents have the form of ICU MessageFormat strings. +See `the Formatting Messages chapter of the ICU Guide `_ +for a guide to MessageFormat, and see +`The ICU APIdoc `_ +for full details of the MessageFormat syntax. + +Examples +~~~~~~~~ + +.. code-block:: yaml + :caption: DataFiles/l10n/MyMod/en.yaml + + good_morning: 'Good morning.' + + you_have_arrows: |- + {count, plural, + one {You have one arrow.} + other {You have {count} arrows.} + } + +.. code-block:: yaml + :caption: DataFiles/l10n/MyMod/de.yaml + + good_morning: "Guten Morgen." + you_have_arrows: |- + {count, plural, + one {Du hast ein Pfeil.} + other {Du hast {count} Pfeile.} + } + "Hello {name}!": "Hallo {name}!" + +Select rules can be used to match arbitrary string arguments. +The default keyword ``other`` must always be provided. + +.. code-block:: yaml + :caption: DataFiles/l10n/AdvancedExample/en.yaml + + pc_must_come: {PCGender, select, + male {He is} + female {She is} + other {They are} + } coming with us. + +Numbers have various formatting options and can also be formatted with custom patterns. +See `The ICU Guide `_ + +.. code-block:: yaml + :caption: DataFiles/l10n/AdvancedExample2/en.yaml + + quest_completion: "The quest is {done, number, percent} complete." + # E.g. "You came in 4th place" + ordinal: "You came in {num, ordinal} place." + # E.g. "There is one thing", "There are one hundred things" + spellout: "There {num, plural, one{is {num, spellout} thing} other{are {num, spellout} things}}." + numbers: "{int} and {double, number, integer} are integers, but {double} is a double" + rounding: "{value, number, :: .00}" diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index b1a10b9cfb..dd4ccac831 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -54,25 +54,14 @@ --- -- Return l10n formatting function for the given context. --- Language files should be stored in VFS as `l10n//.yaml`. +-- Localisation files (containing the message names and translations) should be stored in +-- VFS as files of the form `l10n//.yaml`. -- --- Locales usually have the form {lang}_{COUNTRY}, --- where {lang} is a lowercase two-letter language code and {COUNTRY} is an uppercase --- two-letter country code. Capitalization and the separator must have exactly --- this format for language files to be recognized, but when users request a --- locale they do not need to match capitalization and can use hyphens instead of --- underscores. +-- See [Localisation](../modding/localisation.html) for details of the localisation file structure. -- --- Locales may also contain variants and keywords. See https://unicode-org.github.io/icu/userguide/locale/#language-code --- for full details. --- --- Messages have the form of ICU MessageFormat strings. --- See https://unicode-org.github.io/icu/userguide/format_parse/messages/ --- for a guide to MessageFormat, and see --- https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1MessageFormat.html --- for full details of the MessageFormat syntax. -- @function [parent=#core] l10n -- @param #string context l10n context; recommended to use the name of the mod. +-- This must match the directory in the VFS which stores the localisation files. -- @param #string fallbackLocale The source locale containing the default messages -- If omitted defaults to "en" -- @return #function @@ -80,39 +69,21 @@ -- # DataFiles/l10n/MyMod/en.yaml -- good_morning: 'Good morning.' -- --- you_have_arrows: |- {count, plural, +-- you_have_arrows: |- +-- {count, plural, -- one {You have one arrow.} -- other {You have {count} arrows.} -- } -- @usage -- # DataFiles/l10n/MyMod/de.yaml -- good_morning: "Guten Morgen." --- you_have_arrows: |- {count, plural, +-- you_have_arrows: |- +-- {count, plural, -- one {Du hast ein Pfeil.} -- other {Du hast {count} Pfeile.} -- } -- "Hello {name}!": "Hallo {name}!" -- @usage --- # DataFiles/l10n/AdvancedExample/en.yaml --- # More complicated patterns --- # select rules can be used to match arbitrary string arguments --- # The default keyword other must always be provided --- pc_must_come: {PCGender, select, --- male {He is} --- female {She is} --- other {They are} --- } coming with us. --- # Numbers have various formatting options --- quest_completion: "The quest is {done, number, percent} complete.", --- # E.g. "You came in 4th place" --- ordinal: "You came in {num, ordinal} place." --- # E.g. "There is one thing", "There are one hundred things" --- spellout: "There {num, plural, one{is {num, spellout} thing} other{are {num, spellout} things}}." --- numbers: "{int} and {double, number, integer} are integers, but {double} is a double" --- # Numbers can be formatted with custom patterns --- # See https://unicode-org.github.io/icu/userguide/format_parse/numbers/skeletons.html#syntax --- rounding: "{value, number, :: .00}" --- @usage -- -- Usage in Lua -- local myMsg = core.l10n('MyMod', 'en') -- print( myMsg('good_morning') ) From 2f455aa87bd2f0ebca375dc799bb9bb455759a4d Mon Sep 17 00:00:00 2001 From: Benjamin Winger Date: Tue, 12 Apr 2022 14:11:55 -0400 Subject: [PATCH 2/2] Added fallback details to l10n docs --- docs/source/reference/modding/localisation.rst | 11 +++++++++++ files/lua_api/openmw/core.lua | 9 ++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/source/reference/modding/localisation.rst b/docs/source/reference/modding/localisation.rst index c0bf766d66..bc66053d58 100644 --- a/docs/source/reference/modding/localisation.rst +++ b/docs/source/reference/modding/localisation.rst @@ -19,6 +19,17 @@ and can also use hyphens instead of underscores. The locale will be normalised t Locales may also contain variants and keywords, though these usually will not be necessary. See `The Locale chapter of the ICU Guide `_ for full details. +Fallbacks +--------- + +When OpenMW looks up messages at runtime, it starts with the first requested locale, and then looks at that locale's more generic ancestors before looking at the next requested locale. E.g. ``en_GB_OED`` will fall back to ``en_GB``, which will fall back to ``en``. + +When including localisations with specific country variants (or more specific variants/keywords), you should always include the more generic version as well. + +E.g. if you include ``en_US.yaml`` and ``en_GB.yaml`` localisation files, you should also include ``en.yaml``, since other English locales will fall back to that (e.g. ``en_CA``, ``en_AU``, ``en_NZ``). You can put an arbitrary ``en`` locale of your choice in ``en.yaml``, and then leave the file for that variant empty (since all lookups for the variant will fall back to ``en`` anyway). + +Note that because of the fallbacks only messages which differ between variants need to be included in the country-specific localisation files. + Localisation Files -------------------------- diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index dd4ccac831..d719853da0 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -59,11 +59,18 @@ -- -- See [Localisation](../modding/localisation.html) for details of the localisation file structure. -- +-- When calling the l10n formatting function, if no localisation can be found for any of the requested locales then +-- the message key will be returned instead (and formatted, if possible). +-- This makes it possible to use the source strings as message identifiers. +-- +-- If you do not use the source string as a message identifier you should instead make certain to include +-- a fallback locale with a complete set of messages. +-- -- @function [parent=#core] l10n -- @param #string context l10n context; recommended to use the name of the mod. -- This must match the directory in the VFS which stores the localisation files. -- @param #string fallbackLocale The source locale containing the default messages --- If omitted defaults to "en" +-- If omitted defaults to "en". -- @return #function -- @usage -- # DataFiles/l10n/MyMod/en.yaml