10

I am looking for an idempotent ansible role/task to ensure a certain locale (like en_US.UTF-8) is set as default. It should generate the locale (only if necessary) and set it as a default (also only if necessary).

For the first part I'd register the output of locale -a | grep "{{ locale_name }}" and generate if needed.

For the second part I'm wondering if running update-locale every time is good enough because that command itself is idempotent anyway.

2
  • 2
    For the first part see locale_gen. For the second, what is update-locale? That's not the way to set the locale on a modern Linux system (and I can't even find it!), localectl is. – Michael Hampton Mar 19 '19 at 22:42
  • update-locale is the command that works on all Debian-family systems. It does the same as localectl and the question remains the same (for the second part). :) – mniess Apr 2 '19 at 17:13
12

The localectl command from @mniess answer will always report as "changed" even if the new values are the equal to the current ones. Here's what I personally ended up to set both LANG and LANGUAGE and solve that issue:

- name: Ensure localisation files for '{{ config_system_locale }}' are available
  locale_gen:
    name: "{{ config_system_locale }}"
    state: present

- name: Ensure localisation files for '{{ config_system_language }}' are available
  locale_gen:
    name: "{{ config_system_language }}"
    state: present

- name: Get current locale and language configuration
  command: localectl status
  register: locale_status
  changed_when: false

- name: Parse 'LANG' from current locale and language configuration
  set_fact:
    locale_lang: "{{ locale_status.stdout | regex_search('LANG=([^\n]+)', '\\1') | first }}"

- name: Parse 'LANGUAGE' from current locale and language configuration
  set_fact:
    locale_language: "{{ locale_status.stdout | regex_search('LANGUAGE=([^\n]+)', '\\1') | default([locale_lang], true) | first }}"

- name: Configure locale to '{{ config_system_locale }}' and language to '{{ config_system_language }}'
  command: localectl set-locale LANG={{ config_system_locale }} LANGUAGE={{ config_system_language }}
  changed_when: locale_lang != config_system_locale or locale_language != config_system_language

Also, this what I have at group_vars/main.yml:

config_system_locale: 'pt_PT.UTF-8'
config_system_language: 'en_US.UTF-8'
2
  • Thanks! You could also change changed_when: to when: on the last line to skip that command altogether when the locale is already set correctly. – danmichaelo Jan 22 '20 at 14:32
  • 1
    Note: Won't work on RHEL/CentOS – ALex_hha Jun 2 '20 at 15:34
6

Here is what I ended up with:

- name: Ensure the locale exists
  locale_gen:
    name: en_US.UTF-8
    state: present
- name: set as default locale
  command: localectl set-locale LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8
0

While rfgamaral's answer is great, it only works in Debian because the locale_gen community module does not support RHEL. To support both RHEL/CentOS and Debian, try the following:

- name: check if locale exists
  shell: "locale -a | grep -i {{ config_system_locale | regex_replace('-', '') | quote }}"
  register: found_locale
  changed_when: no
  failed_when: no

- name: create locale
  command: "localedef -i {{ config_system_locale | regex_replace('(.*)\\..*', '\\1') | quote }} -f {{ config_system_locale | regex_replace('.*\\.(.*)', '\\1') | quote }} {{ config_system_locale | quote }}"
  when: not ansible_check_mode and found_language.rc != 0

- name: check if language exists
  shell: "locale -a | grep -i {{ config_system_language | regex_replace('-', '') | quote }}"
  register: found_language
  changed_when: no
  failed_when: no

- name: create language
  command: "localedef -i {{ config_system_language | regex_replace('(.*)\\..*', '\\1') | quote }} -f {{ config_system_language | regex_replace('.*\\.(.*)', '\\1') | quote }} {{ config_system_language | quote }}"
  when: not ansible_check_mode and found_language.rc != 0

- name: Get current locale and language configuration
  command: localectl status
  register: locale_status
  changed_when: false

- name: Parse 'LANG' from current locale and language configuration
  set_fact:
    locale_lang: "{{ locale_status.stdout | regex_search('LANG=([^\n]+)', '\\1') | first }}"

- name: Parse 'LANGUAGE' from current locale and language configuration
  set_fact:
    locale_language: "{{ locale_status.stdout | regex_search('LANGUAGE=([^\n]+)', '\\1') | default([locale_lang], true) | first }}"

- name: Configure locale to '{{ config_system_locale }}' and language to '{{ config_system_language }}'
  command: localectl set-locale LANG={{ config_system_locale }} LANGUAGE={{ config_system_language }}
  changed_when: locale_lang != config_system_locale or locale_language != config_system_language

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.