Anyone that knows me knows that I love Languages. My first job was at Bachtrack, the world's largest online classical musical listing website, where I was hired to help facilitate the migration into other languages. It was here where I became acutely aware of the issues that come with internationalisation, and why it needs to be dealt with upfront, as had been done at Bachtrack!
Internationalisation, however, goes far beyond just the words on the screen. Think about how the CTAs on a Hebrew or Arabic website change sides, or how the feel of a Japanese website is markedly different to what we are accustomed to here in the West. A lot of frontend styling libraries, like Tailwind and Bootstrap, no longer have a concept of "left" and "right", but rather "start" and "end" to help developers think about Right To Left writing systems. Flutter widgets do the same.
For the text of your website, one can use the builtin translation system, but I wasn't too much of a fan of it. I looked around and found Slang, which felt like I could have my translation strings stored in a fashion similar to what I'm used to in React.
Slang
Slang is a "type-safe i18n solution using JSON, YAML or CSV files."
pubspec.yaml
dependencies:
...
slang: ^3.23.0
slang_flutter: ^3.23.0
dev_dependencies:
...
build_runner: ^2.4.6
slang_build_runner: ^3.23.0
flutter pub get
I used the following configuration so that I could use multiple files (e.g.
login.json
and dashboard.json
all nested under ./libs/i18n/en/
). build.yaml
targets:
$default:
builders:
slang_build_runner:
options:
base_locale: en
fallback_strategy: base_locale
input_directory: lib/i18n
input_file_pattern: .i18n.json
output_directory: lib/i18n
output_file_name: translations.g.dart
output_format: multiple_files
namespaces: true
string_interpolation: double_braces
login.json
{
"login": "Login",
"email": "Email address",
"password": "Password"
}
Slang compiles your JSON files down to a the builtin translation system, either by running the command
dart run slang
or by using the build runner flutter pub run build_runner watch --delete-conflicting-outputs
. This generates the relevant files which will then allow you to use your new translation strings like soimport 'package:app/i18n/translations.g.dart';
final fieldName = t.login.email;
Note,
.g.dart
is a common filename pattern you'll see. It simply means that the file was generated - for which there are a lot of Dart and Flutter packages that want to generate code for you.