patch 9.1.0509: not possible to translate Vim script messages

Problem:  not possible to translate Vim script messages
          (RestorerZ)
Solution: implement bindtextdomain() and gettext() to support Vim script
          message translations (Christ van Willegen)

fixes: #11637
closes: #12447

Signed-off-by: Christ van Willegen <cvwillegen@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index c1dd260..34c0b0a 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -1,4 +1,4 @@
-*builtin.txt*	For Vim version 9.1.  Last change: 2024 Jun 19
+*builtin.txt*	For Vim version 9.1.  Last change: 2024 Jun 20
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -67,6 +67,8 @@
 balloon_gettext()		String	current text in the balloon
 balloon_show({expr})		none	show {expr} inside the balloon
 balloon_split({msg})		List	split {msg} as used for a balloon
+bindtextdomain({package}, {path})
+				none	bind text domain to specied path
 blob2list({blob})		List	convert {blob} into a list of numbers
 browse({save}, {title}, {initdir}, {default})
 				String	put up a file requester
@@ -277,7 +279,8 @@
 gettabwinvar({tabnr}, {winnr}, {name} [, {def}])
 				any	{name} in {winnr} in tab page {tabnr}
 gettagstack([{nr}])		Dict	get the tag stack of window {nr}
-gettext({text})			String	lookup translation of {text}
+gettext({text} [, {package}])
+				String	lookup translation of {text}
 getwininfo([{winid}])		List	list of info about each window
 getwinpos([{timeout}])		List	X and Y coord in pixels of Vim window
 getwinposx()			Number	X coord in pixels of the Vim window
@@ -1218,6 +1221,13 @@
 
 		Return type: list<any> or list<string>
 
+bindtextdomain({package}, {path})			*bindtextdomain()*
+		Bind a specific {package} to a {path} so that the
+		|gettext()| function can be used to get language-specific
+		translations for a package.  {path} is the directory name
+		for the translations. See |package-create|.
+
+		Return type: none
 
 blob2list({blob})					*blob2list()*
 		Return a List containing the number value of each byte in Blob
@@ -4978,7 +4988,7 @@
 		Return type: dict<any>
 
 
-gettext({text})						*gettext()*
+gettext({text} [, {package}])				*gettext()*
 		Translate String {text} if possible.
 		This is mainly for use in the distributed Vim scripts.  When
 		generating message translations the {text} is extracted by
@@ -4988,6 +4998,9 @@
 		For {text} double quoted strings are preferred, because
 		xgettext does not understand escaping in single quoted
 		strings.
+		When the {package} is specified, the translation is looked up
+		for that specific package. You need to specify the path to
+		look for translations with the |bindtextdomain()| function.
 
 		Return type: |String|
 
diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt
index e95b6a1..0bfb117 100644
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -1,4 +1,4 @@
-*repeat.txt*    For Vim version 9.1.  Last change: 2023 May 26
+*repeat.txt*    For Vim version 9.1.  Last change: 2024 Jun 20
 
 
 		  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -735,6 +735,10 @@
    start/foobar/autoload/foo.vim	" loaded when foo command used
    start/foobar/doc/foo.txt		" help for foo.vim
    start/foobar/doc/tags		" help tags
+   start/foobar/lang/<lang_id>/LC_MESSAGES/foo.po
+					" messages for the plugin in the
+					" <lang_id> language.  These files are
+					" optional.
    opt/fooextra/plugin/extra.vim	" optional plugin, defines commands
    opt/fooextra/autoload/extra.vim	" loaded when extra command used
    opt/fooextra/doc/extra.txt		" help for extra.vim
@@ -762,6 +766,35 @@
 	:helptags path/start/foobar/doc
 	:helptags path/opt/fooextra/doc
 
+The messages that are in the lang/<lang_id>/LC_MESSAGES/foo.po file need to be
+translated to a format that the |gettext()| function understands by running the
+msgfmt program. This will result in a lang/<lang_id>/LC_MESSAGES/foo.mo
+file. See |multilang| on how to specify languages.
+
+In your plugin, you need to call the |bindtextdomain()| function as follows.
+This assumes that the directory structure is as above: >
+	:call bindtextdomain("foo", fnamemodify(expand("<script>"), ':p:h')
+	 .. '/../lang/')
+<
+You only need to do this once. After this call, you can use: >
+	:echo gettext("Hello", "foo")
+<
+to get the text "Hello" translated to the user's preferred language (if the
+plugin messages have been translated to this language).
+
+To create the foo.po file, you need to create a foo.pot file first. The
+entries in this file need to be translated to the language(s) you want to be
+supported by your plugin.
+
+To create the foo.pot file, run the following command: >
+	cd ~/.vim/pack/start/foobar
+	make -f ~/src/vim/src/po/Makefile PACKAGE=foo \
+	PO_BASEDIR=~/src/vim/src/po PO_INPUTLIST= \
+	PO_VIM_JSLIST="plugin__foo.js plugin__bar.js \
+	autoload__foo.js" \
+	PO_VIM_INPUTLIST="plugin/foo.vim plugin/bar.vim autoload/foo.vim" \
+	foo.pot
+<
 
 Dependencies between plugins ~
 							*packload-two-steps*
diff --git a/runtime/doc/tags b/runtime/doc/tags
index 4dd25ba..46f15ab 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -6148,6 +6148,7 @@
 beval_winid-variable	eval.txt	/*beval_winid-variable*
 beval_winnr-variable	eval.txt	/*beval_winnr-variable*
 binary-number	eval.txt	/*binary-number*
+bindtextdomain()	builtin.txt	/*bindtextdomain()*
 bitwise-function	usr_41.txt	/*bitwise-function*
 bitwise-shift	eval.txt	/*bitwise-shift*
 blob	eval.txt	/*blob*
@@ -10598,6 +10599,7 @@
 termdebug-prompt	terminal.txt	/*termdebug-prompt*
 termdebug-starting	terminal.txt	/*termdebug-starting*
 termdebug-stepping	terminal.txt	/*termdebug-stepping*
+termdebug-timeout	terminal.txt	/*termdebug-timeout*
 termdebug-variables	terminal.txt	/*termdebug-variables*
 termdebug_disasm_window	terminal.txt	/*termdebug_disasm_window*
 termdebug_map_K	terminal.txt	/*termdebug_map_K*
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index a54a991..922e80a 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -798,6 +798,7 @@
 	execute()		execute an Ex command and get the output
 	win_execute()		like execute() but in a specified window
 	trim()			trim characters from a string
+	bindtextdomain()	set message lookup translation base path
 	gettext()		lookup message translation
 
 List manipulation:					*list-functions*
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index d50e0e8..b60f386 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -41563,6 +41563,9 @@
 Support highlighting the matched text for insert-mode completion and
 command-line completion in |ins-completion-menu|.
 
+Support for translating messages in Vim script plugins using the |gettext()|
+and |bindtextdomain()| functions.
+
 							*changed-9.2*
 Changed~
 -------
@@ -41579,6 +41582,7 @@
 
 Functions: ~
 
+|bindtextdomain()|	set message lookup translation base path
 |diff()|		diff two Lists of strings
 |filecopy()|		copy a file {from} to {to}
 |foreach()|		apply function to List items