excel2l10n 1.0.0 copy "excel2l10n: ^1.0.0" to clipboard
excel2l10n: ^1.0.0 copied to clipboard

A tool to convert excel to l10n files.

excel2l10n #

pub package

A Dart tool that reads localization data from a spreadsheet (e.g. Feishu / Lark) and generates localization files for Flutter projects. Supports simple text, typed placeholders, plurals, gender/select, ordinals, and raw ICU strings — all expressed directly in a spreadsheet table.

Installation #

Add to your project's dev dependencies:

dart pub add dev:excel2l10n

Quick Start #

  1. Create excel2l10n.yaml in your project root
  2. Fill in your spreadsheet data following the table format
  3. Run:
dart run excel2l10n

Configuration (excel2l10n.yaml) #

platform:
  name: feishu                          # Currently only feishu is supported
  app_id: cli_xxxxxxxxxxxxxxxx          # From https://open.feishu.cn/
  app_secret: xxxxxxxxxxxxxxxxxxxxxxxx  # From https://open.feishu.cn/
  spreadsheet_token: xxxxxxxxxxx        # Token in your spreadsheet URL

target: arb          # arb | getx | localizations
output_dir: output   # Output directory

If the target requires extra options, use the object form:

target:
  name: localizations
  className: L
  outputFileName: app_localizations
  genExtension: false

Table Format #

The spreadsheet must have the following column layout:

key description en zh
  • key and description are required as the first two columns.
  • All subsequent columns are language codes (en, zh, ja, etc.).
  • Do not leave empty columns in the middle.
  • Multiple sheets are supported; entries from all sheets are merged (later sheets override earlier ones on duplicate keys).

Layer 1 — Simple Text #

key description en zh
greeting Greeting on home page Hello! 你好!

Layer 2 — Typed Placeholders #

Use {name} for a String placeholder, or {name:type} to specify the type.

Supported types: string (default), int, double, num, datetime

key description en zh
welcome Hello, {name} 你好,{name}
fileSize {size:double} MB {size:double} MB
countdown {days:int} days left 剩余 {days:int} 天

Layer 3 — Plural #

Use @plural(pivotVar) in the description of the parent row, then add sub-rows with key[form] keys.

Supported forms: zero, one, two, few, many, other

key description en zh
itemCount @plural(count)
itemCount[one] {count} item {count} 件
itemCount[other] {count} items {count} 件

Layer 3 — Select / Gender #

Use @select(pivotVar) in the description. Case names can be anything (e.g. male, female, other).

key description en zh
userTitle @select(gender)
userTitle[male] Mr. {name} {name} 先生
userTitle[female] Ms. {name} {name} 女士
userTitle[other] Mx. {name} {name}

Layer 3 — Ordinal #

Use @ordinal(pivotVar). Forms follow the same set as plural.

key description en zh
rankLabel @ordinal(position)
rankLabel[one] {position}st 第 {position} 名
rankLabel[two] {position}nd 第 {position} 名
rankLabel[few] {position}rd 第 {position} 名
rankLabel[other] {position}th 第 {position} 名

Layer 4 — Raw ICU Pass-through #

For complex nested ICU expressions (e.g. plural inside select), mark the description as @icu and write the ICU string directly in each language cell.

key description en zh
complexMsg @icu {gender, select, male{{count, plural, one{He has 1} other{He has {count}}}} other{...}}

Adding a Description Alongside an Annotation #

Any text after the annotation (separated by a newline or space) is treated as the entry's human-readable description and will be used as a doc comment in generated code.

key description en zh
userTitle @select(gender)
性别称谓
itemCount @plural(count)
商品数量

Targets #

arb #

Generates .arb files compatible with Flutter's gen_l10n tool.

target:
  name: arb
  genL10nYaml: true   # Also generate l10n.yaml (default: false)

Output (one file per language, e.g. app_en.arb):

{
  "@@locale": "en",
  "greeting": "Hello!",
  "@greeting": { "description": "Greeting on home page" },
  "welcome": "Hello, {name}",
  "@welcome": {
    "placeholders": { "name": { "type": "String" } }
  },
  "itemCount": "{count, plural, one{{count} item} other{{count} items}}",
  "@itemCount": {
    "placeholders": { "count": { "type": "num" } }
  }
}
Option Type Default Description
genL10nYaml bool false Generate l10n.yaml in the project root

getx #

Generates two Dart files for use with GetX:

  • locales_helper.g.dart — abstract class L with static const key strings
  • locales.g.dartMyLocale extends Translations with the full translation map

Plural / Select / Ordinal entries are stored as raw ICU strings (pair with an ICU-aware library at runtime).

target: getx

localizations #

Directly generates .dart files — no need for .arb files or gen_l10n. Suitable when you want full control over the generated API.

target:
  name: localizations
  className: L                      # Abstract class name (default: L)
  outputFileName: app_localizations # Base file name (default: app_localizations)
  genExtension: false               # Generate extension skeleton files (default: false)

Generated files:

File Description
{outputFileName}.dart Abstract class + LMixin with all method signatures
{outputFileName}_{lang}.dart Concrete implementation for each language
extension_{outputFileName}.dart Extension mixin skeleton (when genExtension: true)
extension_{outputFileName}_{lang}.dart Language-specific extension mixin (when genExtension: true)

Rich text (TextSpan) support:

For every entry that has parameters, a Span variant is generated alongside the String method, allowing use with Text.rich / RichText:

Entry type String method TextSpan method
PlaceholderItem String welcome(String name) TextSpan welcomeSpan(InlineSpan name)
PluralItem String itemCount(num count) TextSpan itemCountSpan(num count)
SelectItem String userTitle(String gender, String name) TextSpan userTitleSpan(String gender, InlineSpan name)
OrdinalItem String rankLabel(num position) TextSpan rankLabelSpan(num position)

In the Span variant, the pivot parameter (num/String) stays its original type for runtime selection logic, while additional placeholder parameters become InlineSpan so callers can inject styled widgets.

Note: @icu entries are not supported by the localizations target. A warning is printed at generation time and the entry is skipped. Use the arb target for raw ICU strings.

Usage example:

// String version
Text(L.of(context).welcome('Alice'))

// TextSpan version — style the name differently
Text.rich(
  L.of(context).welcomeSpan(
    TextSpan(text: 'Alice', style: TextStyle(fontWeight: FontWeight.bold)),
  ),
)

// Plural
Text(L.of(context).itemCount(3))

// Plural with styled count
Text.rich(
  L.of(context).itemCountSpan(
    3,
    // The num pivot renders as plain text inside the span by default
  ),
)

genExtension option:

When true, skeleton mixin files are generated that you can fill in with custom overrides. These files are never overwritten on subsequent runs, so your customizations are preserved.


Platform: Feishu / Lark #

platform:
  name: feishu
  app_id: cli_xxxxxxxxxxxxxxxx
  app_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  spreadsheet_token: xxxxxxxxxxxxxxxxxxxxxxxxxxx
Field Description
app_id App ID from Feishu Open Platform
app_secret App Secret from Feishu Open Platform
spreadsheet_token Token in the spreadsheet URL: https://xxx.feishu.cn/sheets/{spreadsheet_token}

All sheets in the spreadsheet are fetched and merged automatically.


Full Configuration Example #

platform:
  name: feishu
  app_id: cli_xxxxxxxxxxxxxxxx
  app_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  spreadsheet_token: xxxxxxxxxxxxxxxxxxxxxxxxxxx

target:
  name: localizations
  className: L
  outputFileName: app_localizations
  genExtension: true

output_dir: lib/l10n

Run with a custom config file path:

dart run excel2l10n --config path/to/config.yaml
# or
dart run excel2l10n -c path/to/config.yaml
1
likes
140
points
205
downloads

Documentation

API reference

Publisher

verified publishernysm.dev

Weekly Downloads

A tool to convert excel to l10n files.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

args, dart_style, dio, meta, pub_semver, yaml

More

Packages that depend on excel2l10n