legalize-es-spanish-legislation

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Legalize ES — Spanish Legislation Git Repository

Legalize ES — 西班牙立法Git仓库

Skill by ara.so — Daily 2026 Skills collection.
ara.so提供的Skill — 2026年度技能合集收录项目。

What It Is

项目说明

legalize-es
is a Git repository containing 8,600+ Spanish laws as Markdown files, with every legislative reform recorded as a Git commit. Each law is a single
.md
file named by its BOE identifier (e.g.
BOE-A-1978-31229.md
for the Spanish Constitution). Reform history goes back to 1960.
Key capabilities:
  • Full text search across all laws with
    grep
  • Exact diff between any two versions of a law using
    git diff
  • Timeline of all reforms to a specific law using
    git log
  • Historical state of any law at any point in time using
    git show
    /
    git checkout

legalize-es
是一个Git仓库,收录了8600+条西班牙法律的Markdown文件,每一次立法修订都会记录为一次Git commit。每部法律对应一个
.md
文件,以BOE编号命名(例如西班牙宪法对应的文件为
BOE-A-1978-31229.md
)。修订历史最早可追溯至1960年。
核心功能:
  • 使用
    grep
    在所有法律中进行全文搜索
  • 使用
    git diff
    对比同一法律任意两个版本的差异
  • 使用
    git log
    查看特定法律的所有修订时间线
  • 使用
    git show
    /
    git checkout
    查看任意时间点的法律历史版本

Setup

安装部署

bash
undefined
bash
undefined

Clone the full repo (includes all history)

克隆完整仓库(包含所有历史记录)

Shallow clone if you only need current state (much faster)

如果仅需要当前版本可以使用浅克隆,速度更快

git clone --depth 1 https://github.com/legalize-dev/legalize-es.git cd legalize-es

All law files live in the `spain/` directory.

---
git clone --depth 1 https://github.com/legalize-dev/legalize-es.git cd legalize-es

所有法律文件都存放在`spain/`目录下。

---

File Structure

文件结构

spain/
├── BOE-A-1978-31229.md    # Constitución Española
├── BOE-A-1995-25444.md    # Código Penal
├── BOE-A-2015-11430.md    # Estatuto de los Trabajadores
├── BOE-A-2000-323.md      # Ley de Enjuiciamiento Civil
└── ... (8,600+ laws)
spain/
├── BOE-A-1978-31229.md    # Constitución Española
├── BOE-A-1995-25444.md    # Código Penal
├── BOE-A-2015-11430.md    # Estatuto de los Trabajadores
├── BOE-A-2000-323.md      # Ley de Enjuiciamiento Civil
└── ... (8600+部法律)

YAML Frontmatter

YAML前置元数据

Every file starts with structured metadata:
yaml
---
titulo: "Constitución Española"
identificador: "BOE-A-1978-31229"
pais: "es"
rango: "constitucion"
fecha_publicacion: "1978-12-29"
ultima_actualizacion: "2024-02-17"
estado: "vigente"
fuente: "https://www.boe.es/eli/es/c/1978/12/27/(1)"
---
rango
values:
  • constitucion
  • ley-organica
  • ley
  • real-decreto-ley
  • real-decreto-legislativo
estado
values:
  • vigente
    — currently in force
  • derogado
    — repealed

每个文件开头都包含结构化元数据:
yaml
---
titulo: "Constitución Española"
identificador: "BOE-A-1978-31229"
pais: "es"
rango: "constitucion"
fecha_publicacion: "1978-12-29"
ultima_actualizacion: "2024-02-17"
estado: "vigente"
fuente: "https://www.boe.es/eli/es/c/1978/12/27/(1)"
---
rango
字段可选值:
  • constitucion
  • ley-organica
  • ley
  • real-decreto-ley
  • real-decreto-legislativo
estado
字段可选值:
  • vigente
    — 当前生效
  • derogado
    — 已废止

Key Commands

常用命令

Find a Law by Topic

按主题查找法律

bash
undefined
bash
undefined

Search law titles in frontmatter

在前置元数据的法律标题中搜索

grep -rl "trabajo" spain/ | head -20
grep -rl "trabajo" spain/ | head -20

Search for a keyword across all law bodies

在所有法律正文中搜索关键词

grep -rl "huelga" spain/
grep -rl "huelga" spain/

Case-insensitive search for a concept

概念的不区分大小写搜索

grep -rli "protección de datos" spain/
undefined
grep -rli "protección de datos" spain/
undefined

Read a Specific Article

读取具体条款

bash
undefined
bash
undefined

Find Article 18 of the Constitution

查找宪法第18条

grep -A 20 "Artículo 18" spain/BOE-A-1978-31229.md
grep -A 20 "Artículo 18" spain/BOE-A-1978-31229.md

Find an article with context (10 lines before, 30 after)

查找条款并附带上下文(前10行,后30行)

grep -B 10 -A 30 "Artículo 135" spain/BOE-A-1978-31229.md
undefined
grep -B 10 -A 30 "Artículo 135" spain/BOE-A-1978-31229.md
undefined

Find a Law by Its BOE Identifier

按BOE编号查找法律

bash
undefined
bash
undefined

If you know the BOE ID

如果你知道完整BOE ID

cat spain/BOE-A-1995-25444.md
cat spain/BOE-A-1995-25444.md

Search by partial identifier

按部分编号搜索

ls spain/ | grep "BOE-A-1995"
undefined
ls spain/ | grep "BOE-A-1995"
undefined

Filter by Law Type

按法律类型筛选

bash
undefined
bash
undefined

List all Organic Laws

列出所有组织法

grep -rl 'rango: "ley-organica"' spain/
grep -rl 'rango: "ley-organica"' spain/

List all currently active laws

列出所有当前生效的法律

grep -rl 'estado: "vigente"' spain/
grep -rl 'estado: "vigente"' spain/

List all repealed laws

列出所有已废止的法律

grep -rl 'estado: "derogado"' spain/

---
grep -rl 'estado: "derogado"' spain/

---

Git History Commands

Git历史查询命令

See All Reforms to a Law

查看法律的所有修订记录

bash
undefined
bash
undefined

Full reform history of the Spanish Constitution

西班牙宪法的完整修订历史

git log --oneline -- spain/BOE-A-1978-31229.md
git log --oneline -- spain/BOE-A-1978-31229.md

With dates

显示修订日期

git log --format="%h %ad %s" --date=short -- spain/BOE-A-1978-31229.md
git log --format="%h %ad %s" --date=short -- spain/BOE-A-1978-31229.md

With full commit messages (includes reform source URL)

显示完整commit信息(包含修订来源URL)

git log -- spain/BOE-A-1978-31229.md
undefined
git log -- spain/BOE-A-1978-31229.md
undefined

Diff Between Two Versions

两个版本的差异对比

bash
undefined
bash
undefined

Diff of a specific reform commit

查看某一次修订commit的diff

git show 6660bcf -- spain/BOE-A-1978-31229.md
git show 6660bcf -- spain/BOE-A-1978-31229.md

Diff between two commits

对比两次commit的差异

git diff 6660bcf^..6660bcf -- spain/BOE-A-1978-31229.md
git diff 6660bcf^..6660bcf -- spain/BOE-A-1978-31229.md

Diff between two dates

对比两个日期的版本差异

git diff $(git rev-list -1 --before="2011-01-01" HEAD)
$(git rev-list -1 --before="2012-01-01" HEAD)
-- spain/BOE-A-1978-31229.md
undefined
git diff $(git rev-list -1 --before="2011-01-01" HEAD)
$(git rev-list -1 --before="2012-01-01" HEAD)
-- spain/BOE-A-1978-31229.md
undefined

Read Historical Version of a Law

读取法律的历史版本

bash
undefined
bash
undefined

State of the Constitution as of 2010-01-01

2010-01-01时的宪法版本

git show $(git rev-list -1 --before="2010-01-01" HEAD):spain/BOE-A-1978-31229.md
git show $(git rev-list -1 --before="2010-01-01" HEAD):spain/BOE-A-1978-31229.md

Check out law at a specific commit (read-only inspection)

查看特定commit对应的法律版本(只读查看)

git show abc1234:spain/BOE-A-1978-31229.md
undefined
git show abc1234:spain/BOE-A-1978-31229.md
undefined

Find When a Specific Text Was Added or Removed

查找特定文本的增删时间

bash
undefined
bash
undefined

Find which commit introduced "estabilidad presupuestaria"

查找引入"estabilidad presupuestaria"的commit

git log -S "estabilidad presupuestaria" -- spain/BOE-A-1978-31229.md
git log -S "estabilidad presupuestaria" -- spain/BOE-A-1978-31229.md

Find which commit changed a specific phrase

查找修改特定表述的commit

git log -G "límite de déficit estructural" --oneline -- spain/BOE-A-1978-31229.md

---
git log -G "límite de déficit estructural" --oneline -- spain/BOE-A-1978-31229.md

---

Programmatic Access Patterns

程序化访问方案

Shell Script: Extract All Law Titles

Shell脚本:提取所有法律标题

bash
#!/bin/bash
bash
#!/bin/bash

Extract titles and identifiers from all laws

提取所有法律的标题和编号

for file in spain/.md; do id=$(grep 'identificador:' "$file" | head -1 | sed 's/.: "//;s/".//') title=$(grep 'titulo:' "$file" | head -1 | sed 's/.: "//;s/".*//') echo "$id | $title" done
undefined
for file in spain/.md; do id=$(grep 'identificador:' "$file" | head -1 | sed 's/.: "//;s/".//') title=$(grep 'titulo:' "$file" | head -1 | sed 's/.: "//;s/".*//') echo "$id | $title" done
undefined

Shell Script: Find Laws Updated After a Date

Shell脚本:查找指定日期后更新的法律

bash
#!/bin/bash
bash
#!/bin/bash

Laws updated after 2023-01-01

筛选2023-01-01之后更新的法律

TARGET_DATE="2023-01-01" grep -rl "ultima_actualizacion:" spain/ | while read file; do date=$(grep 'ultima_actualizacion:' "$file" | head -1 | grep -o '[0-9]{4}-[0-9]{2}-[0-9]{2}') if [[ "$date" > "$TARGET_DATE" ]]; then echo "$date $file" fi done | sort -r
undefined
TARGET_DATE="2023-01-01" grep -rl "ultima_actualizacion:" spain/ | while read file; do date=$(grep 'ultima_actualizacion:' "$file" | head -1 | grep -o '[0-9]{4}-[0-9]{2}-[0-9]{2}') if [[ "$date" > "$TARGET_DATE" ]]; then echo "$date $file" fi done | sort -r
undefined

Python: Parse Law Frontmatter

Python:解析法律前置元数据

python
import os
import yaml

def parse_law(filepath):
    """Parse a law Markdown file and return frontmatter + body."""
    with open(filepath, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Extract YAML frontmatter between --- delimiters
    if content.startswith('---'):
        parts = content.split('---', 2)
        if len(parts) >= 3:
            metadata = yaml.safe_load(parts[1])
            body = parts[2].strip()
            return metadata, body
    
    return {}, content
python
import os
import yaml

def parse_law(filepath):
    """解析法律Markdown文件,返回前置元数据和正文。"""
    with open(filepath, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # 提取---分隔符之间的YAML前置元数据
    if content.startswith('---'):
        parts = content.split('---', 2)
        if len(parts) >= 3:
            metadata = yaml.safe_load(parts[1])
            body = parts[2].strip()
            return metadata, body
    
    return {}, content

Example: list all active laws

示例:列出所有生效法律

laws_dir = 'spain' active_laws = []
for filename in os.listdir(laws_dir): if filename.endswith('.md'): filepath = os.path.join(laws_dir, filename) meta, body = parse_law(filepath) if meta.get('estado') == 'vigente': active_laws.append({ 'id': meta.get('identificador'), 'titulo': meta.get('titulo'), 'rango': meta.get('rango'), 'ultima_actualizacion': meta.get('ultima_actualizacion'), })
laws_dir = 'spain' active_laws = []
for filename in os.listdir(laws_dir): if filename.endswith('.md'): filepath = os.path.join(laws_dir, filename) meta, body = parse_law(filepath) if meta.get('estado') == 'vigente': active_laws.append({ 'id': meta.get('identificador'), 'titulo': meta.get('titulo'), 'rango': meta.get('rango'), 'ultima_actualizacion': meta.get('ultima_actualizacion'), })

Sort by last update

按最后更新时间排序

active_laws.sort(key=lambda x: x['ultima_actualizacion'] or '', reverse=True) for law in active_laws[:10]: print(f"{law['ultima_actualizacion']} [{law['rango']}] {law['titulo']}")
undefined
active_laws.sort(key=lambda x: x['ultima_actualizacion'] or '', reverse=True) for law in active_laws[:10]: print(f"{law['ultima_actualizacion']} [{law['rango']}] {law['titulo']}")
undefined

Python: Get Reform History via Git

Python:通过Git获取修订历史

python
import subprocess
import json

def get_reform_history(boe_id):
    """Get all commits that modified a law file."""
    filepath = f"spain/{boe_id}.md"
    result = subprocess.run(
        ['git', 'log', '--format=%H|%ad|%s', '--date=short', '--', filepath],
        capture_output=True, text=True
    )
    reforms = []
    for line in result.stdout.strip().split('\n'):
        if line:
            hash_, date, subject = line.split('|', 2)
            reforms.append({'hash': hash_, 'date': date, 'subject': subject})
    return reforms
python
import subprocess
import json

def get_reform_history(boe_id):
    """获取修改某部法律文件的所有commit。"""
    filepath = f"spain/{boe_id}.md"
    result = subprocess.run(
        ['git', 'log', '--format=%H|%ad|%s', '--date=short', '--', filepath],
        capture_output=True, text=True
    )
    reforms = []
    for line in result.stdout.strip().split('\n'):
        if line:
            hash_, date, subject = line.split('|', 2)
            reforms.append({'hash': hash_, 'date': date, 'subject': subject})
    return reforms

Example usage

示例用法

history = get_reform_history('BOE-A-1978-31229') for reform in history: print(f"{reform['date']} {reform['hash'][:7]} {reform['subject']}")
undefined
history = get_reform_history('BOE-A-1978-31229') for reform in history: print(f"{reform['date']} {reform['hash'][:7]} {reform['subject']}")
undefined

Python: Compare Two Versions of a Law

Python:对比法律的两个版本

python
import subprocess

def diff_law_versions(boe_id, commit_before, commit_after):
    """Get unified diff between two versions of a law."""
    filepath = f"spain/{boe_id}.md"
    result = subprocess.run(
        ['git', 'diff', f'{commit_before}..{commit_after}', '--', filepath],
        capture_output=True, text=True
    )
    return result.stdout

def get_law_at_date(boe_id, date_str):
    """Get the text of a law as it was on a given date (YYYY-MM-DD)."""
    filepath = f"spain/{boe_id}.md"
    # Find the last commit before date
    rev = subprocess.run(
        ['git', 'rev-list', '-1', f'--before={date_str}', 'HEAD'],
        capture_output=True, text=True
    ).stdout.strip()
    
    if not rev:
        return None
    
    content = subprocess.run(
        ['git', 'show', f'{rev}:{filepath}'],
        capture_output=True, text=True
    ).stdout
    return content
python
import subprocess

def diff_law_versions(boe_id, commit_before, commit_after):
    """获取法律两个版本的统一diff。"""
    filepath = f"spain/{boe_id}.md"
    result = subprocess.run(
        ['git', 'diff', f'{commit_before}..{commit_after}', '--', filepath],
        capture_output=True, text=True
    )
    return result.stdout

def get_law_at_date(boe_id, date_str):
    """获取指定日期(YYYY-MM-DD)时的法律文本。"""
    filepath = f"spain/{boe_id}.md"
    # 查找指定日期前的最后一次commit
    rev = subprocess.run(
        ['git', 'rev-list', '-1', f'--before={date_str}', 'HEAD'],
        capture_output=True, text=True
    ).stdout.strip()
    
    if not rev:
        return None
    
    content = subprocess.run(
        ['git', 'show', f'{rev}:{filepath}'],
        capture_output=True, text=True
    ).stdout
    return content

Example: see Constitution before and after 2011 reform

示例:查看2011年宪法修订前后的版本

old_text = get_law_at_date('BOE-A-1978-31229', '2011-09-26') new_text = get_law_at_date('BOE-A-1978-31229', '2011-09-28') print("Pre-reform length:", len(old_text)) print("Post-reform length:", len(new_text))
undefined
old_text = get_law_at_date('BOE-A-1978-31229', '2011-09-26') new_text = get_law_at_date('BOE-A-1978-31229', '2011-09-28') print("修订前长度:", len(old_text)) print("修订后长度:", len(new_text))
undefined

Python: Search Across All Laws

Python:在所有法律中搜索

python
import os
import re

def search_laws(query, laws_dir='spain', rango=None, estado='vigente'):
    """Search for a regex pattern across all laws."""
    results = []
    pattern = re.compile(query, re.IGNORECASE)
    
    for filename in os.listdir(laws_dir):
        if not filename.endswith('.md'):
            continue
        filepath = os.path.join(laws_dir, filename)
        with open(filepath, 'r', encoding='utf-8') as f:
            content = f.read()
        
        # Filter by frontmatter fields
        if estado and f'estado: "{estado}"' not in content:
            continue
        if rango and f'rango: "{rango}"' not in content:
            continue
        
        matches = list(pattern.finditer(content))
        if matches:
            titulo_match = re.search(r'titulo: "([^"]+)"', content)
            titulo = titulo_match.group(1) if titulo_match else filename
            results.append({
                'file': filename,
                'titulo': titulo,
                'match_count': len(matches),
                'first_match_context': content[max(0, matches[0].start()-100):matches[0].end()+100]
            })
    
    return sorted(results, key=lambda x: x['match_count'], reverse=True)
python
import os
import re

def search_laws(query, laws_dir='spain', rango=None, estado='vigente'):
    """在所有法律中搜索正则匹配的内容。"""
    results = []
    pattern = re.compile(query, re.IGNORECASE)
    
    for filename in os.listdir(laws_dir):
        if not filename.endswith('.md'):
            continue
        filepath = os.path.join(laws_dir, filename)
        with open(filepath, 'r', encoding='utf-8') as f:
            content = f.read()
        
        # 按前置元数据字段筛选
        if estado and f'estado: "{estado}"' not in content:
            continue
        if rango and f'rango: "{rango}"' not in content:
            continue
        
        matches = list(pattern.finditer(content))
        if matches:
            titulo_match = re.search(r'titulo: "([^"]+)"', content)
            titulo = titulo_match.group(1) if titulo_match else filename
            results.append({
                'file': filename,
                'titulo': titulo,
                'match_count': len(matches),
                'first_match_context': content[max(0, matches[0].start()-100):matches[0].end()+100]
            })
    
    return sorted(results, key=lambda x: x['match_count'], reverse=True)

Example: find all active organic laws mentioning "privacidad"

示例:查找所有提及"privacidad"的生效组织法

hits = search_laws("privacidad", rango="ley-organica") for h in hits: print(f"[{h['match_count']} matches] {h['titulo']}") print(f" Context: ...{h['first_match_context'].strip()[:150]}...") print()

---
hits = search_laws("privacidad", rango="ley-organica") for h in hits: print(f"[{h['match_count']} 匹配项] {h['titulo']}") print(f" 上下文: ...{h['first_match_context'].strip()[:150]}...") print()

---

Common Workflows

常见工作流

Workflow 1: Research a Legal Topic

工作流1:法律主题调研

bash
undefined
bash
undefined

1. Find relevant laws

1. 查找相关法律

grep -rl "protección de datos personales" spain/ > relevant_laws.txt
grep -rl "protección de datos personales" spain/ > relevant_laws.txt

2. Get titles of matching files

2. 获取匹配文件的标题

while read file; do grep 'titulo:' "$file" | head -1 done < relevant_laws.txt
while read file; do grep 'titulo:' "$file" | head -1 done < relevant_laws.txt

3. Find the primary law (LOPD/GDPR implementation)

3. 查找核心法律(LOPD/GDPR落地法规)

grep -rl 'rango: "ley-organica"' spain/ | xargs grep -l "protección de datos"
undefined
grep -rl 'rango: "ley-organica"' spain/ | xargs grep -l "protección de datos"
undefined

Workflow 2: Track a Specific Reform

工作流2:追踪特定修订

bash
undefined
bash
undefined

1. Find when Article 135 changed (2011 constitutional reform)

1. 查找第135条的修改时间(2011年宪法修订)

git log -S "estabilidad presupuestaria" --oneline -- spain/BOE-A-1978-31229.md
git log -S "estabilidad presupuestaria" --oneline -- spain/BOE-A-1978-31229.md

2. View the exact changes

2. 查看具体修改内容

git show <commit-hash> -- spain/BOE-A-1978-31229.md
git show <commit-hash> -- spain/BOE-A-1978-31229.md

3. Read the commit message for official source

3. 读取commit信息获取官方来源

git show --format="%B" <commit-hash> | head -10
undefined
git show --format="%B" <commit-hash> | head -10
undefined

Workflow 3: Export Laws to JSON

工作流3:导出法律数据为JSON

python
import os, yaml, json

laws = []
for fname in os.listdir('spain'):
    if not fname.endswith('.md'):
        continue
    with open(f'spain/{fname}', 'r', encoding='utf-8') as f:
        content = f.read()
    if content.startswith('---'):
        parts = content.split('---', 2)
        if len(parts) >= 3:
            meta = yaml.safe_load(parts[1])
            meta['filename'] = fname
            laws.append(meta)

with open('laws_index.json', 'w', encoding='utf-8') as f:
    json.dump(laws, f, ensure_ascii=False, indent=2, default=str)

print(f"Exported {len(laws)} laws")

python
import os, yaml, json

laws = []
for fname in os.listdir('spain'):
    if not fname.endswith('.md'):
        continue
    with open(f'spain/{fname}', 'r', encoding='utf-8') as f:
        content = f.read()
    if content.startswith('---'):
        parts = content.split('---', 2)
        if len(parts) >= 3:
            meta = yaml.safe_load(parts[1])
            meta['filename'] = fname
            laws.append(meta)

with open('laws_index.json', 'w', encoding='utf-8') as f:
    json.dump(laws, f, ensure_ascii=False, indent=2, default=str)

print(f"已导出 {len(laws)} 部法律")

Troubleshooting

问题排查

Repo is Too Large to Clone

仓库太大无法克隆

bash
undefined
bash
undefined

Use shallow clone for current state only

使用浅克隆仅获取当前版本

Or clone with limited history

或者克隆限制历史深度的版本

Git Log Shows No History After Shallow Clone

浅克隆后Git Log没有历史记录

bash
undefined
bash
undefined

Fetch more history

获取更多历史记录

git fetch --deepen=100
git fetch --deepen=100

Fetch full history

获取完整历史记录

git fetch --unshallow
undefined
git fetch --unshallow
undefined

Encoding Issues on Windows

Windows上的编码问题

bash
undefined
bash
undefined

Force UTF-8 in git

强制Git使用UTF-8

git config core.quotepath false git config i18n.logoutputencoding utf-8
git config core.quotepath false git config i18n.logoutputencoding utf-8

In Python, always open files with encoding='utf-8'

Python中打开文件始终指定encoding='utf-8'

undefined
undefined

Finding a Law Without Its BOE ID

没有BOE ID时查找法律

bash
undefined
bash
undefined

Search by partial title (case-insensitive)

按部分标题搜索(不区分大小写)

grep -ril "enjuiciamiento civil" spain/ | head -5
grep -ril "enjuiciamiento civil" spain/ | head -5

Or search in frontmatter only (faster)

或者仅在前缀元数据中搜索(速度更快)

grep -rl "Ley de Enjuiciamiento Civil" spain/

---
grep -rl "Ley de Enjuiciamiento Civil" spain/

---

Data Source & License

数据源与许可证

  • Legislative content: Public domain — sourced from BOE Open Data API
  • Repository structure, metadata, tooling: MIT License
  • Official source per law: See
    fuente:
    field in each file's frontmatter
  • Part of: Legalize multi-country project
  • Upcoming: Programmatic API at legalize.dev
  • 立法内容: 公有领域 — 来源于BOE开放数据API
  • 仓库结构、元数据、工具代码: MIT许可证
  • 每部法律的官方来源: 参见每个文件前置元数据中的
    fuente:
    字段
  • 所属项目: Legalize多国法律项目
  • 即将上线: legalize.dev 程序化API