html
When provisioning servers across different environments, inconsistent locale settings can cause unexpected behavior in applications. The en_US.UTF-8
locale is particularly important as it's the de facto standard for many internationalized applications.
Here's a production-tested solution that handles both locale generation and system-wide configuration:
- name: Ensure required locale is available
become: yes
locale_gen:
name: "{{ locale_name | default('en_US.UTF-8') }}"
state: present
- name: Configure system-wide locale settings
become: yes
block:
- name: Check current locale configuration
command: localectl status
register: current_locale
changed_when: false
- name: Set system locale if needed
command: localectl set-locale "LANG={{ locale_name | default('en_US.UTF-8') }}"
when: >
locale_name | default('en_US.UTF-8') not in current_locale.stdout
The solution combines Ansible's locale_gen
module (for generating locales) with direct localectl
commands (for system configuration). This provides several advantages:
- True idempotency through explicit condition checks
- Support for most modern Linux distributions
- Clear separation between locale generation and system configuration
For environments requiring multiple locale settings, extend the solution with this pattern:
- name: Configure additional locale variables
become: yes
copy:
dest: /etc/default/locale
content: |
LANG={{ primary_locale }}
LC_COLLATE={{ collate_locale }}
LC_CTYPE={{ ctype_locale }}
validate: 'localectl set-locale --file %s'
Always include validation tasks in your playbook:
- name: Verify locale configuration
command: locale
register: locale_output
changed_when: false
- name: Debug locale settings
debug:
msg: "Current locale settings:\n{{ locale_output.stdout }}"
System locales define language, character encoding, and regional settings for applications. The UTF-8 encoded locales (like en_US.UTF-8) have become the standard for modern systems. When automating server configuration with Ansible, we need to ensure both:
- The desired locale is generated (available in the system)
- The locale is set as default system-wide
Here's a robust approach that handles both requirements idempotently:
- name: Check if locale exists
command: locale -a | grep "{{ locale_name }}"
register: locale_check
ignore_errors: yes
changed_when: false
- name: Generate locale if missing
become: yes
command: locale-gen {{ locale_name }}
when: locale_check.rc != 0
- name: Update default locale
become: yes
command: update-locale LANG={{ locale_name }} LC_ALL={{ locale_name }}
register: locale_update
changed_when: "'No changes' not in locale_update.stdout"
For production use, consider this enhanced version with variables and error handling:
---
# vars/main.yml
default_locale: en_US.UTF-8
supported_locales:
- en_US.UTF-8
- fr_FR.UTF-8
# tasks/main.yml
- name: Install locale packages
become: yes
apt:
name: "{{ item }}"
state: present
loop:
- locales
- language-pack-en
- name: Ensure locales are generated
become: yes
command: locale-gen {{ item }}
loop: "{{ supported_locales }}"
when: item not in locale_check.stdout
- name: Set system default locale
become: yes
copy:
dest: /etc/default/locale
content: |
LANG={{ default_locale }}
LC_ALL={{ default_locale }}
notify: Refresh locale
The solution needs adjustment for RHEL/CentOS systems:
- name: Install locales package (RHEL)
become: yes
yum:
name: glibc-common
state: present
- name: Generate locale (RHEL)
become: yes
command: localedef -c -i en_US -f UTF-8 en_US.UTF-8
Always include verification steps in your playbook:
- name: Verify current locale settings
command: locale
register: locale_status
changed_when: false
- name: Debug locale settings
debug:
msg: "{{ locale_status.stdout_lines }}"