Discussion:
Changing language input method by addressee
Bob Newell
2018-03-09 05:13:09 UTC
Permalink
Aloha everyone,

I mostly correspond in English, but I have a few French correspondents
and a couple of German ones. So I wanted to automatically enter French
input mode or German input mode respectively when writing to one of
those folks. After an embarrassing amount of time I came up with
something that works. (I'm on Emacs 25.3 and corresponding Gnus, and I
use message mode, gnus-alias, and BBDB completion. Obviously, I've
anonymized the addressees.)

--

(defun rjn-change-lang-by-addressee (&rest args)
(let* ((addressee (message-fetch-field "To")))
(if addressee
(if (or
(string-match-p "french1" addressee)
(string-match-p "french2" addressee)
(string-match-p "french3" addressee)
(string-match-p "french4" addressee)
(string-match-p "french5" addressee)
(string-match-p "french6" addressee)
(string-match-p "french7" addressee)
(string-match-p "french8" addressee))
(set-input-method "french-postfix")
(if (or
(string-match-p "german1" addressee)
(string-match-p "german2" addressee)
(string-match-p "german3" addressee))
(set-input-method "german-postfix"))))))

(add-hook 'message-setup-hook 'rjn-change-lang-by-addressee t)
(advice-add 'bbdb-complete-mail :after #'rjn-change-lang-by-addressee)

--

But this seems excessively crude and clunky. Surely I'm not the first
person ever to do this sort of thing, but I can't find any other
examples.

Any suggestions about doing this better, perhaps much better?

Mahalo,
--
Bob Newell
Honolulu, Hawai`i
* Via Gnus/BBDB/Org/Emacs/Linux *
Eric Abrahamsen
2018-03-09 07:15:16 UTC
Permalink
Post by Bob Newell
Aloha everyone,
I mostly correspond in English, but I have a few French correspondents
and a couple of German ones. So I wanted to automatically enter French
input mode or German input mode respectively when writing to one of
those folks. After an embarrassing amount of time I came up with
something that works. (I'm on Emacs 25.3 and corresponding Gnus, and I
use message mode, gnus-alias, and BBDB completion. Obviously, I've
anonymized the addressees.)
--
(defun rjn-change-lang-by-addressee (&rest args)
(let* ((addressee (message-fetch-field "To")))
(if addressee
(if (or
(string-match-p "french1" addressee)
(string-match-p "french2" addressee)
(string-match-p "french3" addressee)
(string-match-p "french4" addressee)
(string-match-p "french5" addressee)
(string-match-p "french6" addressee)
(string-match-p "french7" addressee)
(string-match-p "french8" addressee))
(set-input-method "french-postfix")
(if (or
(string-match-p "german1" addressee)
(string-match-p "german2" addressee)
(string-match-p "german3" addressee))
(set-input-method "german-postfix"))))))
(add-hook 'message-setup-hook 'rjn-change-lang-by-addressee t)
(advice-add 'bbdb-complete-mail :after #'rjn-change-lang-by-addressee)
--
But this seems excessively crude and clunky. Surely I'm not the first
person ever to do this sort of thing, but I can't find any other
examples.
Any suggestions about doing this better, perhaps much better?
A small improvement would be to store the addresses elsewhere, say in a
variable, and then use `regexp-opt' on the lists to build one regexp
for French and another for German. Then you can collapse your
`string-match-p' calls to one per language.

A better solution might involve giving your BBDB contacts a "language"
xfield, holding values like "fr" or "de". Then in the
message-setup-hook just retrieve the actual BBDB contact, check if it
has a language xfield, and set the input method accordingly.

HTH,
Eric
Bob Newell
2018-03-09 17:02:59 UTC
Permalink
Post by Eric Abrahamsen
A better solution might involve giving your BBDB contacts a "language"
xfield, holding values like "fr" or "de". Then in the
message-setup-hook just retrieve the actual BBDB contact, check if it
has a language xfield, and set the input method accordingly.
This is really the right way. Then the method is extensible easily to
any number of languages and the language preferences are stored with the
rest of the recipient's info. And there is no need to loop through a
potentially long list.

Many thanks for the idea. I'll go about implementing it.
--
Bob Newell
Honolulu, Hawai`i
* Via Gnus/BBDB/Org/Emacs/Linux *
Tim Landscheidt
2018-03-09 19:18:14 UTC
Permalink
Post by Bob Newell
Post by Eric Abrahamsen
A better solution might involve giving your BBDB contacts a "language"
xfield, holding values like "fr" or "de". Then in the
message-setup-hook just retrieve the actual BBDB contact, check if it
has a language xfield, and set the input method accordingly.
This is really the right way. Then the method is extensible easily to
any number of languages and the language preferences are stored with the
rest of the recipient's info. And there is no need to loop through a
potentially long list.
Many thanks for the idea. I'll go about implementing it.
BTW, I have a similar itch with sentence-end-double-space
which I set to nil when I compose German mails (or other
texts), being able to type:

| (set (make-local-variable 'sentence-end-double-space) nil)

now blindly :-).

I always wanted to solve that more fundamentally: A buffer
(or a part of a buffer?) has an associated language, and
certain properties derive from that, similar to HTML's lang
attribute. Sentence ends, smart quotes, etc. would then
take the buffer's (or point's) language in consideration.

Does Emacs provide some groundwork to build upon for that?

Tim
Bob Newell
2018-03-09 19:36:56 UTC
Permalink
I imagine you could use set-language-environment and
set-language-environment-hook to do what you mention (but of course I've
not tried it!).
--
Bob Newell
Honolulu, Hawai`i
* Via Gnus/BBDB/Org/Emacs/Linux *
Bob Newell
2018-03-09 19:29:45 UTC
Permalink
Aloha everyone,

Just for completeness, here's the final result, and it's much much
better. In BBDB just 'i' a 'language' field for those correspondents
with whom you correspond in whatever language, and then enter the input
mode, like 'french-postfix'. As long as you're using message mode and
BBDB completion, this works. If you use gnu-alias, initialize that
before you get to the code below, as the message-setup-hook I add
should be the last in the chain.

--

(defun rjn-change-lang-by-addressee ()
(interactive)
(let ((addressee (message-fetch-field "To"))
netaddr person langpref)
(if addressee
(setq netaddr (cadr (mail-extract-address-components addressee))))
(if netaddr
(setq person (car (bbdb-search (bbdb-records) :mail netaddr))))
(if person
(setq langpref (bbdb-record-field person 'language)))
(if langpref
(set-input-method langpref))))

(add-hook 'message-setup-hook 'rjn-change-lang-by-addressee t)
(advice-add 'bbdb-complete-mail :after #'rjn-change-lang-by-addressee)

--

This could but shouldn't be simplified with multiple let* assignments,
as nil fields cause error messages to be emitted in some of the
functions. The serial 'if' statements cause negligible additional run
time. If 'langpref' is invalid, there's a message, and that's a good
thing.
--
Bob Newell
Honolulu, Hawai`i
* Via Gnus/BBDB/Org/Emacs/Linux *
Loading...